Repository navigation
Expand file tree
/
Copy pathglobals.h
More file actions
3062 lines (2649 loc) Β· 106 KB
/
Copy pathglobals.h
File metadata and controls
3062 lines (2649 loc) Β· 106 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright 2012 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.
#ifndef V8_COMMON_GLOBALS_H_
#define V8_COMMON_GLOBALS_H_
#include <stddef.h>
#include <stdint.h>
#include <limits>
#include <ostream>
#include "include/cppgc/macros.h"
#include "include/v8-internal.h"
#include "src/base/atomic-utils.h"
#include "src/base/bit-field.h"
#include "src/base/build_config.h"
#include "src/base/enum-set.h"
#include "src/base/flags.h"
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "src/base/numbers/double.h"
#include "src/base/strong-alias.h"
#define V8_INFINITY std::numeric_limits<double>::infinity()
// AIX has jmpbuf redefined as __jmpbuf in /usr/include/sys/context.h
// which replaces v8's jmpbuf , resulting in undefined symbol errors
#if defined(V8_OS_AIX) && defined(jmpbuf)
#undef jmpbuf
#endif
namespace v8 {
namespace base {
class Mutex;
class RecursiveMutex;
} // namespace base
namespace internal {
// Determine whether we are running in a simulated environment.
// Setting USE_SIMULATOR explicitly from the build script will force
// the use of a simulated environment.
#if !defined(USE_SIMULATOR)
#if (V8_TARGET_ARCH_ARM64 && !V8_HOST_ARCH_ARM64)
#define USE_SIMULATOR 1
#endif
#if (V8_TARGET_ARCH_ARM && !V8_HOST_ARCH_ARM)
#define USE_SIMULATOR 1
#endif
#if (V8_TARGET_ARCH_PPC64 && !V8_HOST_ARCH_PPC64)
#define USE_SIMULATOR 1
#endif
#if (V8_TARGET_ARCH_MIPS64 && !V8_HOST_ARCH_MIPS64)
#define USE_SIMULATOR 1
#endif
#if (V8_TARGET_ARCH_S390X && !V8_HOST_ARCH_S390X)
#define USE_SIMULATOR 1
#endif
#if (V8_TARGET_ARCH_RISCV64 && !V8_HOST_ARCH_RISCV64)
#define USE_SIMULATOR 1
#endif
#if (V8_TARGET_ARCH_RISCV32 && !V8_HOST_ARCH_RISCV32)
#define USE_SIMULATOR 1
#endif
#if (V8_TARGET_ARCH_LOONG64 && !V8_HOST_ARCH_LOONG64)
#define USE_SIMULATOR 1
#endif
#endif
#if USE_SIMULATOR
#define USE_SIMULATOR_BOOL true
#else
#define USE_SIMULATOR_BOOL false
#endif
// Determine whether the architecture uses an embedded constant pool
// (contiguous constant pool embedded in code object).
#if V8_TARGET_ARCH_PPC64
#define V8_EMBEDDED_CONSTANT_POOL_BOOL true
#else
#define V8_EMBEDDED_CONSTANT_POOL_BOOL false
#endif
#ifdef DEBUG
#define DEBUG_BOOL true
#else
#define DEBUG_BOOL false
#endif
#ifdef V8_MAP_PACKING
#define V8_MAP_PACKING_BOOL true
#else
#define V8_MAP_PACKING_BOOL false
#endif
#ifdef V8_COMPRESS_POINTERS
#define COMPRESS_POINTERS_BOOL true
#else
#define COMPRESS_POINTERS_BOOL false
#endif
#if V8_TARGET_ARCH_X64 && V8_BUILTINS_GEARBOX
#define V8_ENABLE_GEARBOX true
#else
#define V8_ENABLE_GEARBOX false
#endif // V8_TARGET_ARCH_X64 && V8_BUILTINS_GEARBOX
#if COMPRESS_POINTERS_BOOL && V8_TARGET_ARCH_X64
#define DECOMPRESS_POINTER_BY_ADDRESSING_MODE true
#else
#define DECOMPRESS_POINTER_BY_ADDRESSING_MODE false
#endif
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
#define COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL true
#else
#define COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL false
#endif
#ifdef V8_CONTIGUOUS_COMPRESSED_RO_SPACE
#define CONTIGUOUS_COMPRESSED_READ_ONLY_SPACE_BOOL true
#else
#define CONTIGUOUS_COMPRESSED_READ_ONLY_SPACE_BOOL false
#endif
#if COMPRESS_POINTERS_BOOL && !COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL
#define COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL true
#else
#define COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL false
#endif
#ifndef V8_DISABLE_WRITE_BARRIERS
#define V8_CAN_CREATE_SHARED_HEAP_BOOL true
#else
#define V8_CAN_CREATE_SHARED_HEAP_BOOL false
#endif
#ifdef V8_LOWER_LIMITS_MODE
#define V8_LOWER_LIMITS_MODE_BOOL true
#else
#define V8_LOWER_LIMITS_MODE_BOOL false
#endif
#ifdef V8_STATIC_ROOTS_GENERATION
#define V8_STATIC_ROOTS_GENERATION_BOOL true
#else
#define V8_STATIC_ROOTS_GENERATION_BOOL false
#endif
#ifdef V8_COMPRESS_POINTERS
#define V8_STATIC_DISPATCH_HANDLES_BOOL true
#else
#define V8_STATIC_DISPATCH_HANDLES_BOOL false
#endif // !V8_COMPRESS_POINTERS
#ifdef V8_ENABLE_SANDBOX
#define V8_ENABLE_SANDBOX_BOOL true
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE 1
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL true
#else
#define V8_ENABLE_SANDBOX_BOOL false
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL false
#endif
#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY
#define ENABLE_CONTROL_FLOW_INTEGRITY_BOOL true
#else
#define ENABLE_CONTROL_FLOW_INTEGRITY_BOOL false
#endif
#if V8_TARGET_ARCH_ARM
// Set stack limit lower for ARM than for other architectures because stack
// allocating MacroAssembler takes 120K bytes. See issue crbug.com/405338
#define V8_DEFAULT_STACK_SIZE_KB 864
#elif V8_TARGET_ARCH_IA32
// As of crrev.com/c/2461589, Chrome creates some threads (at least worker
// pools threads, maybe others) on 32-bit Windows with only 512 KB of stack
// space. Since we cannot accurately tell when that's the case, and since
// this platform isn't being used very much any more, we play it safe by
// reducing stack size for all ia32 builds.
// Rationale behind the specific value: leave the same 40 KB of slack as
// the 984 KB limit we used on systems with 1 MB stack size.
#define V8_DEFAULT_STACK_SIZE_KB 472
#elif V8_USE_ADDRESS_SANITIZER
// ASan makes C++ frames consume more stack, so V8 should leave more stack
// space available in case a C++ call happens. ClusterFuzz found a case where
// even just 1 KB less than the default stack size would be enough (see
// crbug.com/1486275); to be more robust towards future CF reports we'll
// use an even lower limit.
#define V8_DEFAULT_STACK_SIZE_KB 960
#else
// Slightly less than 1MB, since Windows' default stack size for
// the main execution thread is 1MB.
#define V8_DEFAULT_STACK_SIZE_KB 984
#endif
// Helper macros to enable handling of direct C calls in the simulator.
#if defined(USE_SIMULATOR) && \
(defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_MIPS64) || \
defined(V8_TARGET_ARCH_LOONG64) || defined(V8_TARGET_ARCH_RISCV64))
#define V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define V8_IF_USE_SIMULATOR(V) , V
#else
#define V8_IF_USE_SIMULATOR(V)
#endif // defined(USE_SIMULATOR) && \
// (defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_MIPS64) || \
// defined(V8_TARGET_ARCH_LOONG64))
// Minimum stack size in KB required by compilers.
constexpr int kStackSpaceRequiredForCompilation = 40;
// In order to emit more efficient stack checks in optimized code,
// deoptimization may implicitly exceed the V8 stack limit by this many bytes.
// Stack checks in functions with `difference between optimized and unoptimized
// stack frame sizes <= slack` can simply emit the simple stack check.
constexpr int kStackLimitSlackForDeoptimizationInBytes = 256;
// Sanity-check, assuming that we aim for a real OS stack size of at least 1MB.
static_assert(V8_DEFAULT_STACK_SIZE_KB * KB +
kStackLimitSlackForDeoptimizationInBytes <=
MB);
// The V8_ENABLE_NEAR_CODE_RANGE_BOOL enables logic that tries to allocate
// code range within a pc-relative call/jump proximity from embedded builtins.
// This machinery could help only when we have an opportunity to choose where
// to allocate code range and could benefit from it. This is the case for the
// following configurations:
// - external code space AND pointer compression are enabled,
// - short builtin calls feature is enabled while pointer compression is not.
#if (defined(V8_SHORT_BUILTIN_CALLS) && !defined(V8_COMPRESS_POINTERS)) || \
defined(V8_EXTERNAL_CODE_SPACE)
#define V8_ENABLE_NEAR_CODE_RANGE_BOOL true
#else
#define V8_ENABLE_NEAR_CODE_RANGE_BOOL false
#endif
// This constant is used for detecting whether the machine has >= 4GB of
// physical memory by checking the max old space size.
const size_t kShortBuiltinCallsOldSpaceSizeThreshold = size_t{2} * GB;
// Determine whether dict mode prototypes feature is enabled.
#ifdef V8_ENABLE_SWISS_NAME_DICTIONARY
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL true
#else
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL false
#endif
// Determine whether dict property constness tracking feature is enabled.
#ifdef V8_DICT_PROPERTY_CONST_TRACKING
#define V8_DICT_PROPERTY_CONST_TRACKING_BOOL true
#else
#define V8_DICT_PROPERTY_CONST_TRACKING_BOOL false
#endif
#ifdef V8_EXTERNAL_CODE_SPACE
#define V8_EXTERNAL_CODE_SPACE_BOOL true
#else
#define V8_EXTERNAL_CODE_SPACE_BOOL false
#endif
// Support for jump table disassembly.
#if defined(ENABLE_DISASSEMBLER) && \
(defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_X64))
#define V8_JUMP_TABLE_INFO_BOOL true
#else
#define V8_JUMP_TABLE_INFO_BOOL false
#endif
// V8_HEAP_USE_PTHREAD_JIT_WRITE_PROTECT controls how V8 sets permissions for
// executable pages.
// In particular,
// 1) when memory region is reserved for code range, the whole region is
// committed with RWX permissions and then the whole region is discarded,
// 2) since reconfiguration of RWX page permissions is not allowed on MacOS on
// ARM64 ("Apple M1"/Apple Silicon), there must be no attempts to change
// them,
// 3) the request to set RWX permissions in the execeutable page region just
// commits the pages without changing permissions (see (1), they were already
// allocated as RWX and then deommitted),
// 4) in order to make executable pages inaccessible one must use
// OS::DiscardSystemPages() instead of using OS::DecommitPages() or setting
// permissions to kNoAccess because the latter two are not allowed by the
// MacOS (see (2)).
//
// This is applicable only to MacOS on ARM64 ("Apple M1"/Apple Silicon) which
// has a APRR/MAP_JIT machinery for fast W^X permission switching (see
// pthread_jit_write_protect).
//
// This approach doesn't work and shouldn't be used for V8 configuration with
// enabled pointer compression and disabled external code space because
// a) the pointer compression cage has to be reserved with MAP_JIT flag which
// is too expensive,
// b) in case of shared pointer compression cage if the code range will be
// deleted while the cage is still alive then attempt to configure
// permissions of pages that were previously set to RWX will fail.
//
#if V8_HAS_PTHREAD_JIT_WRITE_PROTECT && \
!(defined(V8_COMPRESS_POINTERS) && !defined(V8_EXTERNAL_CODE_SPACE))
#define V8_HEAP_USE_PTHREAD_JIT_WRITE_PROTECT true
#else
#define V8_HEAP_USE_PTHREAD_JIT_WRITE_PROTECT false
#endif
// Protect the JavaScript heap with BrowserEngineKit APIs.
#if V8_HAS_BECORE_JIT_WRITE_PROTECT && \
!(defined(V8_COMPRESS_POINTERS) && !defined(V8_EXTERNAL_CODE_SPACE))
#define V8_HEAP_USE_BECORE_JIT_WRITE_PROTECT true
#else
#define V8_HEAP_USE_BECORE_JIT_WRITE_PROTECT false
#endif
// Protect the JavaScript heap with memory protection keys.
#if V8_HAS_PKU_JIT_WRITE_PROTECT && \
!(defined(V8_COMPRESS_POINTERS) && !defined(V8_EXTERNAL_CODE_SPACE))
#define V8_HEAP_USE_PKU_JIT_WRITE_PROTECT true
#else
#define V8_HEAP_USE_PKU_JIT_WRITE_PROTECT false
#endif
// Determine whether tagged pointers are 8 bytes (used in Torque layouts for
// choosing where to insert padding).
#if V8_TARGET_ARCH_64_BIT && !defined(V8_COMPRESS_POINTERS)
#define TAGGED_SIZE_8_BYTES true
#else
#define TAGGED_SIZE_8_BYTES false
#endif
#if defined(V8_OS_WIN) && defined(V8_TARGET_ARCH_X64)
#define V8_OS_WIN_X64 true
#endif
#if defined(V8_OS_WIN) && defined(V8_TARGET_ARCH_ARM64)
#define V8_OS_WIN_ARM64 true
#endif
#if defined(V8_OS_WIN_X64) || defined(V8_OS_WIN_ARM64)
#define V8_OS_WIN64 true
#endif
// Support for floating point parameters in calls to C.
// It's currently enabled only for the platforms listed below. We don't plan
// to add support for IA32, because it has a totally different approach
// (using FP stack).
#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \
defined(V8_TARGET_ARCH_MIPS64) || defined(V8_TARGET_ARCH_LOONG64) || \
defined(V8_TARGET_ARCH_RISCV64)
#define V8_ENABLE_FP_PARAMS_IN_C_LINKAGE 1
#endif
#ifdef V8_ENABLE_UNDEFINED_DOUBLE
#define V8_UNDEFINED_DOUBLE_BOOL true
#else
#define V8_UNDEFINED_DOUBLE_BOOL false
#endif
#ifdef V8_ENABLE_EXPERIMENTAL_TSA_BUILTINS
#define V8_EXPERIMENTAL_TSA_BUILTINS_BOOL true
#else
#define V8_EXPERIMENTAL_TSA_BUILTINS_BOOL false
#endif
#ifdef V8_ENABLE_EXPERIMENTAL_TQ_TO_TSA
#define V8_EXPERIMENTAL_TQ_TO_TSA_BOOL true
#else
#define V8_EXPERIMENTAL_TQ_TO_TSA_BOOL false
#endif
#ifdef V8_ENABLE_EXPERIMENTAL_TQ_TO_TSA
#ifndef V8_ENABLE_EXPERIMENTAL_TSA_BUILTINS
#error "tq-to-tsa is not supported without tsa builtins"
#endif
#define SELECT_TSA_LEVEL(NO_TSA_MACRO, TSA_MACRO, TQ_TO_TSA_MACRO, ...) \
EXPAND(TQ_TO_TSA_MACRO(__VA_ARGS__))
#elif V8_ENABLE_EXPERIMENTAL_TSA_BUILTINS
#define SELECT_TSA_LEVEL(NO_TSA_MACRO, TSA_MACRO, TQ_TO_TSA_MACRO, ...) \
EXPAND(TSA_MACRO(__VA_ARGS__))
#else
#define SELECT_TSA_LEVEL(NO_TSA_MACRO, TSA_MACRO, TQ_TO_TSA_MACRO, ...) \
EXPAND(NO_TSA_MACRO(__VA_ARGS__))
#endif
#ifdef V8_ENABLE_EXPERIMENTAL_TSA_BUILTINS
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_TSA(TSA_MACRO, CSA_MACRO, ...) EXPAND(TSA_MACRO(__VA_ARGS__))
#else
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_TSA(TSA_MACRO, CSA_MACRO, ...) EXPAND(CSA_MACRO(__VA_ARGS__))
#endif
#define V8_STACK_ALLOCATED CPPGC_STACK_ALLOCATED
// Superclass for classes only using static method functions.
// The subclass of AllStatic cannot be instantiated at all.
class AllStatic {
#ifdef DEBUG
public:
AllStatic() = delete;
#endif
};
// -----------------------------------------------------------------------------
// Constants
constexpr int kMaxInt = 0x7FFFFFFF;
constexpr int kMinInt = -kMaxInt - 1;
constexpr int kMaxInt8 = (1 << 7) - 1;
constexpr int kMinInt8 = -(1 << 7);
constexpr int kMaxUInt8 = (1 << 8) - 1;
constexpr int kMinUInt8 = 0;
constexpr int kMaxInt16 = (1 << 15) - 1;
constexpr int kMinInt16 = -(1 << 15);
constexpr int kMaxUInt16 = (1 << 16) - 1;
constexpr int kMinUInt16 = 0;
constexpr int kMaxInt31 = kMaxInt / 2;
constexpr int kMinInt31 = kMinInt / 2;
constexpr uint32_t kMaxUInt32 = 0xFFFF'FFFFu;
constexpr uint32_t kMinUInt32 = 0;
constexpr uint64_t kMaxUInt64 = 0xFFFF'FFFF'FFFF'FFFFu;
constexpr uint64_t kMinUInt64 = 0;
constexpr int kInt8Size = sizeof(int8_t);
constexpr int kUInt8Size = sizeof(uint8_t);
constexpr int kByteSize = 1;
constexpr int kCharSize = sizeof(char);
constexpr int kShortSize = sizeof(short); // NOLINT
constexpr int kInt16Size = sizeof(int16_t);
constexpr int kUInt16Size = sizeof(uint16_t);
constexpr int kIntSize = sizeof(int);
constexpr int kInt32Size = sizeof(int32_t);
constexpr int kUInt32Size = sizeof(uint32_t);
constexpr int kInt64Size = sizeof(int64_t);
constexpr int kUInt64Size = sizeof(uint64_t);
constexpr int kSizetSize = sizeof(size_t);
constexpr int kFloat16Size = sizeof(uint16_t);
constexpr int kFloatSize = sizeof(float);
constexpr int kDoubleSize = sizeof(double);
constexpr int kIntptrSize = sizeof(intptr_t);
constexpr int kUIntptrSize = sizeof(uintptr_t);
constexpr int kSystemPointerSize = sizeof(void*);
constexpr int kSystemPointerHexDigits = kSystemPointerSize == 4 ? 8 : 12;
constexpr int kPCOnStackSize = kSystemPointerSize;
constexpr int kFPOnStackSize = kSystemPointerSize;
#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32
constexpr int kElidedFrameSlots = kPCOnStackSize / kSystemPointerSize;
#else
constexpr int kElidedFrameSlots = 0;
#endif
constexpr int kDoubleSizeLog2 = 3;
// The maximal length of the string representation for a double value
// (e.g. "-2.2250738585072020E-308"). It is composed as follows:
// - 17 decimal digits, see base::kBase10MaximalLength (dtoa.h)
// - 1 sign
// - 1 decimal point
// - 1 E or e
// - 1 exponent sign
// - 3 exponent
constexpr int kMaxDoubleStringLength = 24;
// Total wasm code space per engine (i.e. per process) is limited to make
// certain attacks that rely on heap spraying harder.
// Do not access directly, but via the {--wasm-max-committed-code-mb} flag.
// Just below 4GB, such that {kMaxWasmCodeMemory} fits in a 32-bit size_t.
constexpr uint32_t kMaxCommittedWasmCodeMB = 4095;
// The actual maximum code space size used can be configured with
// --max-wasm-code-space-size. This constant is the default value, and at the
// same time the maximum allowed value (checked by the WasmCodeManager).
#if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_LOONG64
// ARM64 and Loong64 only supports direct calls within a 128 MB range.
constexpr uint32_t kDefaultMaxWasmCodeSpaceSizeMb = 128;
#elif V8_TARGET_ARCH_PPC64
// Branches only take 26 bits.
constexpr uint32_t kDefaultMaxWasmCodeSpaceSizeMb = 32;
#else
// Use 1024 MB limit for code spaces on other platforms. This is smaller than
// the total allowed code space (kMaxWasmCodeMemory) to avoid unnecessarily
// big reservations, and to ensure that distances within a code space fit
// within a 32-bit signed integer.
constexpr uint32_t kDefaultMaxWasmCodeSpaceSizeMb = 1024;
#endif
// Align IsolateData to a most common CPU cache line size.
constexpr size_t kIsolateDataAlignment = 64;
#if V8_HOST_ARCH_64_BIT
constexpr int kSystemPointerSizeLog2 = 3;
constexpr intptr_t kIntptrSignBit =
static_cast<intptr_t>(uintptr_t{0x8000000000000000});
constexpr bool kPlatformRequiresCodeRange = true;
#if V8_HOST_ARCH_PPC64 && V8_TARGET_ARCH_PPC64 && V8_OS_LINUX
constexpr size_t kMaximalCodeRangeSize = 512 * MB;
constexpr size_t kMinExpectedOSPageSize = 64 * KB; // OS page on PPC Linux
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_LOONG64 || V8_TARGET_ARCH_RISCV64
constexpr size_t kMaximalCodeRangeSize =
(COMPRESS_POINTERS_BOOL && !V8_EXTERNAL_CODE_SPACE_BOOL) ? 128 * MB
: 256 * MB;
constexpr size_t kMinExpectedOSPageSize = 4 * KB; // OS page.
#elif V8_TARGET_ARCH_X64
constexpr size_t kMaximalCodeRangeSize =
(COMPRESS_POINTERS_BOOL && !V8_EXTERNAL_CODE_SPACE_BOOL) ? 128 * MB
: 512 * MB;
constexpr size_t kMinExpectedOSPageSize = 4 * KB; // OS page.
#else
constexpr size_t kMaximalCodeRangeSize = 128 * MB;
constexpr size_t kMinExpectedOSPageSize = 4 * KB; // OS page.
#endif
constexpr size_t kMinimumCodeRangeSize = 64 * MB;
#if V8_OS_WIN
constexpr size_t kReservedCodeRangePages = 1;
#else
constexpr size_t kReservedCodeRangePages = 0;
#endif
// These constants define the total trusted space memory per process.
constexpr size_t kMaximalTrustedRangeSize = 1 * GB;
constexpr size_t kMinimumTrustedRangeSize = 512 * MB;
#else // V8_HOST_ARCH_64_BIT
constexpr int kSystemPointerSizeLog2 = 2;
constexpr intptr_t kIntptrSignBit = 0x80000000;
#if V8_HOST_ARCH_PPC64 && V8_TARGET_ARCH_PPC64 && V8_OS_LINUX
constexpr bool kPlatformRequiresCodeRange = false;
constexpr size_t kMaximalCodeRangeSize = 0 * MB;
constexpr size_t kMinimumCodeRangeSize = 0 * MB;
constexpr size_t kMinExpectedOSPageSize = 64 * KB; // OS page on PPC Linux
#elif V8_TARGET_ARCH_RISCV32
constexpr bool kPlatformRequiresCodeRange = false;
constexpr size_t kMaximalCodeRangeSize = 256 * MB;
constexpr size_t kMinimumCodeRangeSize = 0 * MB;
constexpr size_t kMinExpectedOSPageSize = 4 * KB; // OS page.
#else
constexpr bool kPlatformRequiresCodeRange = false;
constexpr size_t kMaximalCodeRangeSize = 0 * MB;
constexpr size_t kMinimumCodeRangeSize = 0 * MB;
constexpr size_t kMinExpectedOSPageSize = 4 * KB; // OS page.
#endif
constexpr size_t kReservedCodeRangePages = 0;
#endif // V8_HOST_ARCH_64_BIT
static_assert(kSystemPointerSize == (1 << kSystemPointerSizeLog2));
#ifdef V8_COMPRESS_POINTERS
static_assert(
kSystemPointerSize == kInt64Size,
"Pointer compression can be enabled only for 64-bit architectures");
constexpr int kTaggedSize = kInt32Size;
constexpr int kTaggedSizeLog2 = 2;
// These types define raw and atomic storage types for tagged values stored
// on V8 heap.
using Tagged_t = uint32_t;
using AtomicTagged_t = base::Atomic32;
#else
constexpr int kTaggedSize = kSystemPointerSize;
constexpr int kTaggedSizeLog2 = kSystemPointerSizeLog2;
// These types define raw and atomic storage types for tagged values stored
// on V8 heap.
using Tagged_t = Address;
using AtomicTagged_t = base::AtomicWord;
#endif // V8_COMPRESS_POINTERS
// The name used for virtual address space reservations backing the pointer
// tables. This name is mostly useful for debugging/inspecting and should be
// visible in e.g. /proc/$pid/maps if the system supports setting names on
// virtual memory ranges (PR_SET_VMA_ANON_NAME on Linux).
// TODO(saelo): It might be nicer to have one name per table type, e.g.
// v8-external-pointer-table, v8-trusted-pointer-table, etc.
static const char* kPointerTableAddressSpaceName = "v8-pointer-table";
//
// JavaScript Dispatch Table
//
// A JSDispatchHandle represents a 32-bit index into a JSDispatchTable.
struct JSDispatchHandleAliasTag {};
using JSDispatchHandle = base::StrongAlias<JSDispatchHandleAliasTag, uint32_t>;
constexpr JSDispatchHandle kNullJSDispatchHandle(0);
constexpr int kJSDispatchTableEntrySize = 16;
constexpr int kJSDispatchTableEntrySizeLog2 = 4;
// The size of the virtual memory reservation for the JSDispatchTable.
// As with the other tables, a maximum table size in combination with shifted
// indices allows omitting bounds checks.
constexpr size_t kJSDispatchTableReservationSize =
(V8_LOWER_LIMITS_MODE_BOOL ? 16 : 256) * MB;
// The maximum number of entries in a JSDispatchTable.
constexpr size_t kMaxJSDispatchEntries =
kJSDispatchTableReservationSize / kJSDispatchTableEntrySize;
#ifdef V8_TARGET_ARCH_64_BIT
constexpr uint32_t kJSDispatchHandleShift = V8_LOWER_LIMITS_MODE_BOOL ? 12 : 8;
static_assert((1 << (32 - kJSDispatchHandleShift)) == kMaxJSDispatchEntries,
"kJSDispatchTableReservationSize and kJSDispatchEntryHandleShift "
"don't match");
#elif defined(V8_TARGET_ARCH_32_BIT)
// Since the table is not contiguous on 32 bit platforms the indices can become
// arbitrarily large and we need the full 32 bit range to hold them.
constexpr uint32_t kJSDispatchHandleShift = 0;
#endif
static_assert(kTaggedSize == (1 << kTaggedSizeLog2));
static_assert((kTaggedSize == 8) == TAGGED_SIZE_8_BYTES);
using AsAtomicTagged = base::AsAtomicPointerImpl<AtomicTagged_t>;
static_assert(sizeof(Tagged_t) == kTaggedSize);
static_assert(sizeof(AtomicTagged_t) == kTaggedSize);
static_assert(kTaggedSize == kApiTaggedSize);
// TODO(ishell): use kTaggedSize or kSystemPointerSize instead.
#ifndef V8_COMPRESS_POINTERS
constexpr int kPointerSize = kSystemPointerSize;
constexpr int kPointerSizeLog2 = kSystemPointerSizeLog2;
static_assert(kPointerSize == (1 << kPointerSizeLog2));
#endif
#ifdef V8_COMPRESS_POINTERS_8GB
// To support 8GB heaps, all allocations are aligned to at least 8 bytes.
#define V8_COMPRESS_POINTERS_8GB_BOOL true
#else
#define V8_COMPRESS_POINTERS_8GB_BOOL false
#endif
// This type defines the raw storage type for external (or off-V8 heap) pointers
// stored on V8 heap.
constexpr int kExternalPointerSlotSize = sizeof(ExternalPointer_t);
#ifdef V8_ENABLE_SANDBOX
static_assert(kExternalPointerSlotSize == kTaggedSize);
#else
static_assert(kExternalPointerSlotSize == kSystemPointerSize);
#endif
// The storage type for pointers referring to CppHeap objects stored on the V8
// heap.
constexpr int kCppHeapPointerSlotSize = sizeof(CppHeapPointer_t);
#ifdef V8_COMPRESS_POINTERS
static_assert(kCppHeapPointerSlotSize == sizeof(uint32_t));
#else
static_assert(kCppHeapPointerSlotSize == kSystemPointerSize);
#endif
constexpr int kIndirectPointerSize = sizeof(IndirectPointerHandle);
// When the sandbox is enabled, trusted pointers are implemented as indirect
// pointers (indices into the trusted pointer table). Otherwise they are regular
// tagged pointers.
#ifdef V8_ENABLE_SANDBOX
constexpr int kTrustedPointerSize = kIndirectPointerSize;
using TrustedPointer_t = TrustedPointerHandle;
#else
constexpr int kTrustedPointerSize = kTaggedSize;
using TrustedPointer_t = Tagged_t;
#endif
constexpr int kCodePointerSize = kTrustedPointerSize;
// Pointers between trusted objects use compressed pointers with the trusted
// space base when the sandbox is enabled. Otherwise, they are regular tagged
// pointers. Either way, they are always kTaggedSize fields.
constexpr int kProtectedPointerSize = kTaggedSize;
constexpr int kJSDispatchHandleSize = sizeof(JSDispatchHandle);
// Dispatch handle constant used as a placeholder. This is currently used by
// compilers when generating JS calls. In that case, the actual dispatch handle
// value is only loaded by the low-level MacroAssembler operations, but a
// placeholder value is necessary prior to that to satisfy linkage constraints.
// TODO(saelo): instead, we could let the compiler load the dispatch handle
// from the JSFunction and then use a MacroAssembler operation that uses the
// dispatch handle directly. We just need to be sure that no GC can happen
// between the load of the dispatch handle and the use.
constexpr JSDispatchHandle kPlaceholderDispatchHandle(0x0);
// Dispatch handle constant that can be used for direct calls when it is known
// that the callee doesn't use the dispatch handle. This is for example the
// case when performing direct calls to JS builtins.
constexpr JSDispatchHandle kInvalidDispatchHandle(0xffffffff
<< kJSDispatchHandleShift);
constexpr int kEmbedderDataSlotSize = kSystemPointerSize;
constexpr int kEmbedderDataSlotSizeInTaggedSlots =
kEmbedderDataSlotSize / kTaggedSize;
static_assert(kEmbedderDataSlotSize >= kSystemPointerSize);
constexpr size_t kExternalAllocationSoftLimit =
internal::Internals::kExternalAllocationSoftLimit;
// Maximum object size that gets allocated into regular pages. Objects larger
// than that size are allocated in large object space and are never moved in
// memory. This also applies to new space allocation, since objects are never
// migrated from new space to large object space. Takes double alignment into
// account.
//
// Current value: half of the page size.
constexpr int kMaxRegularHeapObjectSize = (1 << (kPageSizeBits - 1));
constexpr int kBitsPerByte = 8;
constexpr int kBitsPerByteLog2 = 3;
constexpr int kBitsPerSystemPointer = kSystemPointerSize * kBitsPerByte;
constexpr int kBitsPerSystemPointerLog2 =
kSystemPointerSizeLog2 + kBitsPerByteLog2;
constexpr int kBitsPerInt = kIntSize * kBitsPerByte;
// IEEE 754 single precision floating point number bit layout.
constexpr uint32_t kBinary32SignMask = 0x80000000u;
constexpr uint32_t kBinary32ExponentMask = 0x7f800000u;
constexpr uint32_t kBinary32MantissaMask = 0x007fffffu;
constexpr int kBinary32ExponentBias = 127;
constexpr int kBinary32MaxExponent = 0xFE;
constexpr int kBinary32MinExponent = 0x01;
constexpr int kBinary32MantissaBits = 23;
constexpr int kBinary32ExponentShift = 23;
// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
// other bits set.
constexpr uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
constexpr int kOneByteSize = kCharSize;
// 128 bit SIMD value size.
constexpr int kSimd128Size = 16;
// Half of 128 bit SIMD value size.
constexpr int kSimd128HalfSize = kSimd128Size / 2;
// Quarter of 128 bit SIMD value size.
constexpr int kSimd128QuarterSize = kSimd128Size / 4;
// 256 bit SIMD value size.
constexpr int kSimd256Size = 32;
// FUNCTION_ADDR(f) gets the address of a C function f.
#define FUNCTION_ADDR(f) (reinterpret_cast<v8::internal::Address>(f))
// FUNCTION_CAST<F>(addr) casts an address into a function
// of type F. Used to invoke generated code from within C.
template <typename F>
F FUNCTION_CAST(uint8_t* addr) {
return reinterpret_cast<F>(reinterpret_cast<Address>(addr));
}
template <typename F>
F FUNCTION_CAST(Address addr) {
return reinterpret_cast<F>(addr);
}
// Determine whether the architecture uses function descriptors
// which provide a level of indirection between the function pointer
// and the function entrypoint.
#if V8_HOST_ARCH_PPC64 && \
(V8_OS_AIX || (V8_TARGET_ARCH_PPC64 && V8_TARGET_BIG_ENDIAN && \
(!defined(_CALL_ELF) || _CALL_ELF == 1)))
#define USES_FUNCTION_DESCRIPTORS 1
#define FUNCTION_ENTRYPOINT_ADDRESS(f) \
(reinterpret_cast<v8::internal::Address*>( \
&(reinterpret_cast<intptr_t*>(f)[0])))
#else
#define USES_FUNCTION_DESCRIPTORS 0
#endif
constexpr bool StaticStringsEqual(const char* s1, const char* s2) {
for (;; ++s1, ++s2) {
if (*s1 != *s2) return false;
if (*s1 == '\0') return true;
}
}
#if COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL
constexpr size_t kContiguousReadOnlyReservationSize =
V8_CONTIGUOUS_COMPRESSED_RO_SPACE_SIZE_MB * MB;
// Bound the worst case consumption of contiguous RO space across the various
// cages/regions.
static_assert(kMinimumTrustedRangeSize >= 512 * MB);
static_assert(!kPlatformRequiresCodeRange || kMinimumCodeRangeSize >= 64 * MB);
// In this configuration we only allocate RO objects in the first
// `kContiguousReadOnlyReservationSize` of the shared data cage. We also create
// red zones in all cages and reservations that can be used to allocate
// `HeapObject`s. within this range, i.e., trusted cage and code range.
//
// We want the reservation size to be a power-of-2 to allow cheap containment
// checks.
static_assert(base::bits::IsPowerOfTwo(kContiguousReadOnlyReservationSize));
// The mask here can be used to check whether any Tagged<T> (cage doesn't matter
// here) is contained in RO space as follows:
// ((address & kContiguousReadOnlySpaceMask) == 0) => "object in RO space"
// See `HeapLayout::InReadOnlySpace()` for usage.
//
// E.g., for a 8MiB contiguous region:
// ```
// 0x00000000ffffffff // (kPtrComprCageBaseAlignment-1)
// ^ 0x00000000007fffff // (kContiguousReadOnlyReservationSize - 1)
// = 0x00000000ff800000 // kContiguousReadOnlySpaceMask
// ```
constexpr Address kContiguousReadOnlySpaceMask =
(kPtrComprCageBaseAlignment - 1) ^ (kContiguousReadOnlyReservationSize - 1);
#endif // COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL
// -----------------------------------------------------------------------------
// Declarations for use in both the preparser and the rest of V8.
// The Strict Mode (ECMA-262 5th edition, 4.2.2).
enum class LanguageMode : bool { kSloppy, kStrict };
static const size_t LanguageModeSize = 2;
inline size_t hash_value(LanguageMode mode) {
return static_cast<size_t>(mode);
}
inline const char* LanguageMode2String(LanguageMode mode) {
switch (mode) {
case LanguageMode::kSloppy:
return "sloppy";
case LanguageMode::kStrict:
return "strict";
}
UNREACHABLE();
}
inline std::ostream& operator<<(std::ostream& os, LanguageMode mode) {
return os << LanguageMode2String(mode);
}
inline bool is_sloppy(LanguageMode language_mode) {
return language_mode == LanguageMode::kSloppy;
}
inline bool is_strict(LanguageMode language_mode) {
return language_mode != LanguageMode::kSloppy;
}
inline bool is_valid_language_mode(int language_mode) {
return language_mode == static_cast<int>(LanguageMode::kSloppy) ||
language_mode == static_cast<int>(LanguageMode::kStrict);
}
inline LanguageMode construct_language_mode(bool strict_bit) {
return static_cast<LanguageMode>(strict_bit);
}
// Return kStrict if either of the language modes is kStrict, or kSloppy
// otherwise.
inline LanguageMode stricter_language_mode(LanguageMode mode1,
LanguageMode mode2) {
static_assert(LanguageModeSize == 2);
return static_cast<LanguageMode>(static_cast<int>(mode1) |
static_cast<int>(mode2));
}
// A non-keyed store is of the form a.x = foo or a["x"] = foo whereas
// a keyed store is of the form a[expression] = foo.
enum class StoreOrigin { kMaybeKeyed, kNamed };
enum class TypeofMode { kInside, kNotInside };
enum class ContextMode { kNoContextCells, kHasContextCells };
// Whether floating point registers should be saved (and restored).
enum class SaveFPRegsMode { kIgnore, kSave };
// This enum describes the ownership semantics of an indirect pointer.
enum class IndirectPointerMode {
// A regular reference from one HeapObject to another one through an indirect
// pointer, where the referenced object should be kept alive as long as the
// referencing object is alive.
kStrong,
// A reference from one HeapObject to another one through an indirect pointer
// with custom ownership semantics. Used for example for references from
// JSFunctions to Code objects which follow custom weak ownership semantics.
kCustom
};
// Whether arguments are passed on a known stack location or through a
// register.
enum class ArgvMode { kStack, kRegister };
enum class CallApiCallbackMode {
// This version of CallApiCallback used by IC system, it gets additional
// target function argument which is used both for stack trace reconstruction
// in case exception is thrown inside the callback and for callback
// side-effects checking by debugger.
kGeneric,
// The following two versions are used for generating calls from optimized
// code. They don't need to support side effects checking because function
// will be deoptimized when side effects checking is enabled, and they don't
// get the target function because it can be reconstructed from the lazy
// deopt info in case exception is thrown.
// This version is used for compiling code when Isolate profiling or runtime
// call stats is disabled. The code that uses this version must be created
// with a dependency on NoProfilingProtector.
kOptimizedNoProfiling,
// This version contains a dynamic check for enabled profiler and it supports
// runtime call stats.
kOptimized,
};
// This constant is used to indicate that feedback is embedded in the bytecode
// itself.
constexpr int kFeedbackIsEmbedded = -1;
// This constant is used as an sentinel value for embedded feedback in
// byteocode, indicating an uninitialized state.
constexpr int kUninitializedEmbeddedFeedback = 0;
// The bytecode operand index for embedded feedback.
constexpr int kEmbeddedFeedbackOperandIndex = 1;
// These constants are internal duplicates for v8::Intercepted enum values.
constexpr uint8_t kInterceptedNo = 1;
constexpr uint8_t kInterceptedYes = 0;
constexpr size_t kInterceptedSize = 4;
// Invalid pointer value used for passing the "not intercepted" result from
// CallNamedInterceptorXXXX/CallIndexedInterceptorXXX builtins to caller.
constexpr uint32_t kNotInterceptedSentinel = kHeapObjectTag;
// This constant is used as an undefined value when passing source positions.
constexpr int kNoSourcePosition = -1;
// This constant is used to signal the function entry implicit stack check
// bytecode offset.
constexpr int kFunctionEntryBytecodeOffset = -1;
// This constant is used to signal the function exit interrupt budget handling
// bytecode offset.
constexpr int kFunctionExitBytecodeOffset = -1;
// This constant is used to indicate missing deoptimization information.
constexpr int kNoDeoptimizationId = -1;
// Deoptimize bailout kind:
// - Eager: a check failed in the optimized code and deoptimization happens
// immediately.
// - Lazy: the code has been marked as dependent on some assumption which
// is checked elsewhere and can trigger deoptimization the next time the
// code is executed.
enum class DeoptimizeKind : uint8_t {
kEager,
kLazyAfterFastCall,
kLazy,
};
constexpr DeoptimizeKind kFirstDeoptimizeKind = DeoptimizeKind::kEager;
constexpr DeoptimizeKind kLastDeoptimizeKind = DeoptimizeKind::kLazy;
static_assert(static_cast<int>(kFirstDeoptimizeKind) == 0);
constexpr int kDeoptimizeKindCount = static_cast<int>(kLastDeoptimizeKind) + 1;
inline size_t hash_value(DeoptimizeKind kind) {
return static_cast<size_t>(kind);
}
constexpr const char* ToString(DeoptimizeKind kind) {
switch (kind) {
case DeoptimizeKind::kEager:
return "Eager";
case DeoptimizeKind::kLazy:
return "Lazy";
case DeoptimizeKind::kLazyAfterFastCall:
return "LazyAfterfastCall";
}
}
inline std::ostream& operator<<(std::ostream& os, DeoptimizeKind kind) {
return os << ToString(kind);
}
// Indicates whether the lookup is related to sloppy-mode block-scoped
// function hoisting, and is a synthetic assignment for that.
enum class LookupHoistingMode { kNormal, kLegacySloppy };
inline std::ostream& operator<<(std::ostream& os,
const LookupHoistingMode& mode) {
switch (mode) {
case LookupHoistingMode::kNormal:
return os << "normal hoisting";
case LookupHoistingMode::kLegacySloppy:
return os << "legacy sloppy hoisting";
}
UNREACHABLE();
}
static_assert(kSmiValueSize <= 32, "Unsupported Smi tagging scheme");
// Smi sign bit position must be 32-bit aligned so we can use sign extension
// instructions on 64-bit architectures without additional shifts.