This commit is contained in:
2025-11-07 21:16:47 +04:00
parent 760d3cc709
commit 13c7b878d2
2535 changed files with 1011793 additions and 164 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,13 @@
spring.datasource.url=jdbc:h2:mem:devdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.h2.console.enabled=true
spring.liquibase.enabled=false
logging.level.com.example=DEBUG

View File

@@ -0,0 +1,19 @@
server.port=8080
spring.datasource.url=jdbc:h2:mem:frontdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.liquibase.enabled=false
spring.web.resources.static-locations=classpath:/static/
spring.web.resources.add-mappings=true
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.cache.period=3600
server.error.whitelabel.enabled=false

View File

@@ -0,0 +1,12 @@
spring.datasource.url=jdbc:postgresql://localhost:5432/delivery_db
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
spring.liquibase.enabled=false
logging.level.com.example=INFO

View File

@@ -1,7 +1,8 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.5'
id 'io.spring.dependency-management' version '1.1.7'
id 'java'
id 'org.springframework.boot' version '3.5.5'
id 'io.spring.dependency-management' version '1.1.7'
id 'com.github.node-gradle.node' version '7.0.2' // ⬅️ РАСКОММЕНТИРУЙ
}
group = 'com.example'
@@ -9,27 +10,120 @@ version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.liquibase:liquibase-core'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
// ⭐ НАСТРОЙКИ ДЛЯ NODE/REACT
node {
version = '20.18.0'
npmVersion = '10.8.2'
download = true
workDir = file("${project.projectDir}/front")
npmWorkDir = file("${project.projectDir}/front")
}
// ⭐ ЗАДАЧИ ДЛЯ REACT СБОРКИ ТОЛЬКО ДЛЯ FRONT ПРОФИЛЯ
task buildReact(type: NpmTask) {
onlyIf {
// Собираем React только для front профиля или если явно указано
project.hasProperty('buildFront') ||
System.getProperty("spring.profiles.active") == "front"
}
workingDir = file("${project.projectDir}/front")
args = ['run', 'build']
inputs.dir('front/src')
inputs.dir('front/public')
inputs.file('front/package.json')
inputs.file('front/package-lock.json')
inputs.file('front/vite.config.js')
outputs.dir('build/resources/main/static')
}
task copyReactBuild(type: Copy) {
dependsOn buildReact
from "${project.projectDir}/front/dist"
into "${project.buildDir}/resources/main/static"
// Очищаем папку перед копированием
doFirst {
delete "${project.buildDir}/resources/main/static"
}
}
// ⭐ ОБНОВЛЕННАЯ PROCESS RESOURCES
processResources {
dependsOn copyReactBuild
}
tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
// ⭐ LIQUIBASE ЗАДАЧИ ДЛЯ УПРАВЛЕНИЯ МИГРАЦИЯМИ
task liquibaseStatus(type: JavaExec) {
group = "liquibase"
description = "Показать статус миграций"
classpath = sourceSets.main.runtimeClasspath
mainClass = "liquibase.integration.commandline.Main"
args = [
"--driver=org.h2.Driver",
"--url=jdbc:h2:file:./build/liquibase_demo",
"--username=sa",
"--password=",
"--changeLogFile=src/main/resources/db/changelog/db.changelog-master.xml",
"status"
]
}
task liquibaseUpdate(type: JavaExec) {
group = "liquibase"
description = "Применить все ожидающие миграции"
classpath = sourceSets.main.runtimeClasspath
mainClass = "liquibase.integration.commandline.Main"
args = [
"--driver=org.h2.Driver",
"--url=jdbc:h2:file:./build/liquibase_demo",
"--username=sa",
"--password=",
"--changeLogFile=src/main/resources/db/changelog/db.changelog-master.xml",
"update"
]
}
task liquibaseRollback(type: JavaExec) {
group = "liquibase"
description = "Откатить последнюю миграцию"
classpath = sourceSets.main.runtimeClasspath
mainClass = "liquibase.integration.commandline.Main"
args = [
"--driver=org.h2.Driver",
"--url=jdbc:h2:file:./build/liquibase_demo",
"--username=sa",
"--password=",
"--changeLogFile=src/main/resources/db/changelog/db.changelog-master.xml",
"rollbackCount", "1"
]
}

Binary file not shown.

Binary file not shown.

BIN
build/liquibase_demo.mv.db Normal file

Binary file not shown.

View File

@@ -0,0 +1,4 @@
2025-11-07 20:19:06.365331+04:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Таблица "DATABASECHANGELOGLOCK" не найдена
Table "DATABASECHANGELOGLOCK" not found; SQL statement:
SELECT COUNT(*) FROM PUBLIC.DATABASECHANGELOGLOCK [42102-232]

File diff suppressed because one or more lines are too long

View File

@@ -41,7 +41,7 @@
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.518s</div>
<div class="counter">0.531s</div>
<p>duration</p>
</div>
</td>
@@ -79,7 +79,7 @@
</thead>
<tr>
<td class="success">create_WhenValidData_ShouldCreateCustomer()</td>
<td class="success">0.515s</td>
<td class="success">0.528s</td>
<td class="success">passed</td>
</tr>
<tr>
@@ -108,7 +108,7 @@ WARNING: Dynamic loading of agents will be disallowed by default in a future rel
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 25 окт. 2025г., 00:35:22</p>
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 7 нояб. 2025г., 20:57:01</p>
</div>
</div>
</body>

View File

@@ -41,7 +41,7 @@
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.045s</div>
<div class="counter">0.051s</div>
<p>duration</p>
</div>
</td>
@@ -76,7 +76,7 @@
</thead>
<tr>
<td class="success">create_WhenValidData_ShouldCreateDelivery()</td>
<td class="success">0.001s</td>
<td class="success">0.002s</td>
<td class="success">passed</td>
</tr>
<tr>
@@ -91,17 +91,17 @@
</tr>
<tr>
<td class="success">findAll_ShouldReturnAllDeliveries()</td>
<td class="success">0.001s</td>
<td class="success">0.002s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">findById_WhenDeliveryExists_ShouldReturnDelivery()</td>
<td class="success">0.040s</td>
<td class="success">0.043s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">update_WhenDeliveryExists_ShouldUpdateDelivery()</td>
<td class="success">0.001s</td>
<td class="success">0.002s</td>
<td class="success">passed</td>
</tr>
</table>
@@ -114,7 +114,7 @@
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 25 окт. 2025г., 00:35:22</p>
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 7 нояб. 2025г., 20:57:01</p>
</div>
</div>
</body>

View File

@@ -23,7 +23,7 @@
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">7</div>
<div class="counter">9</div>
<p>tests</p>
</div>
</td>
@@ -41,7 +41,7 @@
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.048s</div>
<div class="counter">0.051s</div>
<p>duration</p>
</div>
</td>
@@ -76,7 +76,7 @@
</thead>
<tr>
<td class="success">create_WhenCustomerNotFound_ShouldThrowException()</td>
<td class="success">0.003s</td>
<td class="success">0.001s</td>
<td class="success">passed</td>
</tr>
<tr>
@@ -100,8 +100,18 @@
<td class="success">passed</td>
</tr>
<tr>
<td class="success">findByCustomerId_ShouldReturnCustomerOrders()</td>
<td class="success">0.002s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">findById_WhenOrderExists_ShouldReturnOrder()</td>
<td class="success">0.001s</td>
<td class="success">0.002s</td>
<td class="success">passed</td>
</tr>
<tr>
<td class="success">findByStatus_ShouldReturnOrdersByStatus()</td>
<td class="success">0.002s</td>
<td class="success">passed</td>
</tr>
<tr>
@@ -119,7 +129,7 @@
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 25 окт. 2025г., 00:35:22</p>
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 7 нояб. 2025г., 20:57:01</p>
</div>
</div>
</body>

View File

@@ -20,7 +20,7 @@
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">15</div>
<div class="counter">17</div>
<p>tests</p>
</div>
</td>
@@ -38,7 +38,7 @@
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.611s</div>
<div class="counter">0.633s</div>
<p>duration</p>
</div>
</td>
@@ -82,10 +82,10 @@
<td class="success">
<a href="packages/com.example.service.html">com.example.service</a>
</td>
<td>15</td>
<td>17</td>
<td>0</td>
<td>0</td>
<td>0.611s</td>
<td>0.633s</td>
<td class="success">100%</td>
</tr>
</tbody>
@@ -112,7 +112,7 @@
<td>2</td>
<td>0</td>
<td>0</td>
<td>0.518s</td>
<td>0.531s</td>
<td class="success">100%</td>
</tr>
<tr>
@@ -122,17 +122,17 @@
<td>6</td>
<td>0</td>
<td>0</td>
<td>0.045s</td>
<td>0.051s</td>
<td class="success">100%</td>
</tr>
<tr>
<td class="success">
<a href="classes/com.example.service.OrderServiceTest.html">com.example.service.OrderServiceTest</a>
</td>
<td>7</td>
<td>9</td>
<td>0</td>
<td>0</td>
<td>0.048s</td>
<td>0.051s</td>
<td class="success">100%</td>
</tr>
</tbody>
@@ -146,7 +146,7 @@
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 25 окт. 2025г., 00:35:22</p>
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 7 нояб. 2025г., 20:57:01</p>
</div>
</div>
</body>

View File

@@ -22,7 +22,7 @@
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">15</div>
<div class="counter">17</div>
<p>tests</p>
</div>
</td>
@@ -40,7 +40,7 @@
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">0.611s</div>
<div class="counter">0.633s</div>
<p>duration</p>
</div>
</td>
@@ -83,7 +83,7 @@
<td>2</td>
<td>0</td>
<td>0</td>
<td>0.518s</td>
<td>0.531s</td>
<td class="success">100%</td>
</tr>
<tr>
@@ -93,17 +93,17 @@
<td>6</td>
<td>0</td>
<td>0</td>
<td>0.045s</td>
<td>0.051s</td>
<td class="success">100%</td>
</tr>
<tr>
<td class="success">
<a href="../classes/com.example.service.OrderServiceTest.html">OrderServiceTest</a>
</td>
<td>7</td>
<td>9</td>
<td>0</td>
<td>0</td>
<td>0.048s</td>
<td>0.051s</td>
<td class="success">100%</td>
</tr>
</table>
@@ -116,7 +116,7 @@
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 25 окт. 2025г., 00:35:22</p>
<a href="https://www.gradle.org">Gradle 8.14.3</a> at 7 нояб. 2025г., 20:57:01</p>
</div>
</div>
</body>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd">
<changeSet id="001-create-customers-table" author="kudrinsky">
<createTable tableName="customers">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="email" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="phone" type="VARCHAR(20)"/>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
<column name="updated_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
</createTable>
</changeSet>
<changeSet id="002-create-deliveries-table" author="kudrinsky">
<createTable tableName="deliveries">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="tracking_number" type="VARCHAR(255)">
<constraints nullable="false" unique="true"/>
</column>
<column name="destination" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="delivery_date" type="TIMESTAMP"/>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
<column name="updated_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
</createTable>
</changeSet>
<changeSet id="003-create-orders-table" author="kudrinsky">
<createTable tableName="orders">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="customer_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="fk_orders_customer" references="customers(id)"/>
</column>
<column name="delivery_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="fk_orders_delivery" references="deliveries(id)"/>
</column>
<column name="status" type="VARCHAR(50)">
<constraints nullable="false"/>
</column>
<column name="order_amount" type="DECIMAL(10,2)">
<constraints nullable="false"/>
</column>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
<column name="updated_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
</createTable>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd">
<changeSet id="002-insert-test-customers" author="kudrinsky">
<insert tableName="customers">
<column name="name" value="Петр Петров"/>
<column name="email" value="petr@mail.ru"/>
<column name="phone" value="+79161234567"/>
</insert>
<insert tableName="customers">
<column name="name" value="Иван Иванов"/>
<column name="email" value="ivan@mail.ru"/>
<column name="phone" value="+79169876543"/>
</insert>
<insert tableName="customers">
<column name="name" value="Мария Сидорова"/>
<column name="email" value="maria@mail.ru"/>
<column name="phone" value="+79165544333"/>
</insert>
</changeSet>
<changeSet id="002-insert-test-deliveries" author="kudrinsky">
<insert tableName="deliveries">
<column name="tracking_number" value="TRK001"/>
<column name="destination" value="ул. Гоголя, 34"/>
</insert>
<insert tableName="deliveries">
<column name="tracking_number" value="TRK002"/>
<column name="destination" value="пр. Ленина, 15"/>
</insert>
<insert tableName="deliveries">
<column name="tracking_number" value="TRK003"/>
<column name="destination" value="ул. Пушкина, 22"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.liquibase.org/xml/ns/dbchangelog
https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd">
<!-- ⭐ БАЗОВАЯ СХЕМА С ROLLBACK -->
<changeSet id="001-create-customers-table" author="kudrinsky">
<createTable tableName="customers">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="email" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="phone" type="VARCHAR(20)"/>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
<column name="updated_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
</createTable>
<rollback>
<dropTable tableName="customers"/>
</rollback>
</changeSet>
<changeSet id="002-create-deliveries-table" author="kudrinsky">
<createTable tableName="deliveries">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="tracking_number" type="VARCHAR(255)">
<constraints nullable="false" unique="true"/>
</column>
<column name="destination" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="delivery_date" type="TIMESTAMP"/>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
<column name="updated_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
</createTable>
<rollback>
<dropTable tableName="deliveries"/>
</rollback>
</changeSet>
<changeSet id="003-create-orders-table" author="kudrinsky">
<createTable tableName="orders">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="customer_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="fk_orders_customer" references="customers(id)"/>
</column>
<column name="delivery_id" type="BIGINT">
<constraints nullable="false" foreignKeyName="fk_orders_delivery" references="deliveries(id)"/>
</column>
<column name="status" type="VARCHAR(50)">
<constraints nullable="false"/>
</column>
<column name="order_amount" type="DECIMAL(10,2)">
<constraints nullable="false"/>
</column>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
<column name="updated_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
</createTable>
<rollback>
<dropTable tableName="orders"/>
</rollback>
</changeSet>
<!-- ⭐ ДЕМОНСТРАЦИОННАЯ МИГРАЦИЯ С ROLLBACK -->
<changeSet id="004-add-priority-column" author="kudrinsky">
<addColumn tableName="orders">
<column name="priority" type="VARCHAR(20)" defaultValue="NORMAL" remarks="Приоритет заказа">
<constraints nullable="false"/>
</column>
</addColumn>
<rollback>
<dropColumn tableName="orders" columnName="priority"/>
</rollback>
</changeSet>
<!-- ⭐ НОВАЯ МИГРАЦИЯ -->
<changeSet id="003-add-email-index" author="kudrinsky">
<createIndex tableName="customers" indexName="idx_customers_email">
<column name="email"/>
</createIndex>
<rollback>
<dropIndex tableName="customers" indexName="idx_customers_email"/>
</rollback>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1 @@
.app{font-family:Arial,sans-serif;max-width:1200px;margin:0 auto;padding:20px;color:#6aa1d1}.header{background-color:#646cff;color:#fff;padding:20px;text-align:center;margin-bottom:30px;border-radius:8px}.container{padding:0 20px}.delivery-list{margin-bottom:30px}.deliveries{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:20px;margin-top:20px}.delivery-item{border:1px solid #ddd;padding:15px;border-radius:8px;box-shadow:0 2px 4px #0000001a;background-color:#f9f9f9;text-align:left}.delivery-info h3{margin-top:0;color:#646cff}.status-принято{color:#2e7d32}.status-в-пути{color:#ed6c02}.status-доставлено{color:#2e7d32;font-weight:700}.status-отменено{color:#d32f2f;text-decoration:line-through}.delivery-actions{margin-top:15px;display:flex;gap:10px}.delivery-actions button{padding:5px 10px;cursor:pointer;border-radius:4px;border:1px solid transparent;background-color:#646cff;color:#fff;transition:background-color .25s}.delivery-actions button:hover{background-color:#747bff}.delivery-form{background-color:#f5f5f5;padding:20px;border-radius:8px;margin-bottom:30px;text-align:left}.delivery-form h3{margin-top:0;color:#646cff}.delivery-form label{display:block;margin-bottom:10px}.delivery-form input,.delivery-form select{width:100%;padding:8px;margin-top:5px;box-sizing:border-box;border-radius:4px;border:1px solid #ddd}.form-actions{margin-top:15px;display:flex;gap:10px}.form-actions button{padding:8px 15px;cursor:pointer;border-radius:4px;border:1px solid transparent;background-color:#646cff;color:#fff;transition:background-color .25s}.form-actions button:hover{background-color:#747bff}.form-actions button[type=button]{background-color:#f44336}.form-actions button[type=button]:hover{background-color:#d32f2f}.list-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.stats-link,.back-link{padding:8px 16px;background:#4caf50;color:#fff;text-decoration:none;border-radius:4px;transition:background .3s}.stats-link:hover,.back-link:hover{background:#45a049}.deliveries-container{margin-top:20px}.no-deliveries{text-align:center;color:#666;font-style:italic}.loading,.error{text-align:center;padding:20px;font-size:1.2em}.error{color:#f44336}.stats-container{max-width:800px;margin:0 auto}.stats-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:20px;margin-top:30px}.stat-card{background:#f5f5f5;padding:20px;border-radius:8px;text-align:center;box-shadow:0 2px 4px #0000001a}.stat-card h3{margin-top:0;color:#333}.stat-card p{font-size:24px;font-weight:700;margin:10px 0 0}.delivery-item{border:1px solid #e0e0e0;padding:20px;border-radius:8px;margin-bottom:20px;background-color:#fff;box-shadow:0 2px 8px #00000014}.delivery-number{color:#646cff;margin-top:0;margin-bottom:15px;font-size:1.3em;border-bottom:1px solid #eee;padding-bottom:10px}.delivery-details{margin-bottom:15px}.delivery-details h4,.delivery-customer h4{margin:8px 0;font-size:1.1em;color:#555}.status{font-weight:400;margin:8px 0}.delivery-actions{margin-top:20px;display:flex;gap:10px;border-top:1px solid #eee;padding-top:15px}.delivery-actions button{padding:8px 15px;cursor:pointer;border-radius:4px;border:none;background-color:#646cff;color:#fff;font-size:.9em;transition:background-color .2s}.delivery-actions button:last-child{background-color:#f44336}.delivery-actions button:hover{opacity:.9}:root{font-family:Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424}body{margin:0;padding:0;min-height:100vh}#root{max-width:1280px;margin:0 auto;padding:2rem;text-align:center}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/assets/react.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Delivery Management System</title>
<script type="module" crossorigin src="./assets/index-C8_Yau0T.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-BWtOf8p2.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="com.example.service.CustomerServiceTest" tests="2" skipped="0" failures="0" errors="0" timestamp="2025-10-24T20:35:22.024Z" hostname="MacBook-Air-Oleg.local" time="0.52">
<testsuite name="com.example.service.CustomerServiceTest" tests="2" skipped="0" failures="0" errors="0" timestamp="2025-11-07T16:57:00.489Z" hostname="MacBook-Air-Oleg.local" time="0.532">
<properties/>
<testcase name="create_WhenValidData_ShouldCreateCustomer()" classname="com.example.service.CustomerServiceTest" time="0.515"/>
<testcase name="create_WhenValidData_ShouldCreateCustomer()" classname="com.example.service.CustomerServiceTest" time="0.528"/>
<testcase name="findById_WhenCustomerExists_ShouldReturnCustomer()" classname="com.example.service.CustomerServiceTest" time="0.003"/>
<system-out><![CDATA[]]></system-out>
<system-err><![CDATA[Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="com.example.service.DeliveryServiceTest" tests="6" skipped="0" failures="0" errors="0" timestamp="2025-10-24T20:35:22.547Z" hostname="MacBook-Air-Oleg.local" time="0.049">
<testsuite name="com.example.service.DeliveryServiceTest" tests="6" skipped="0" failures="0" errors="0" timestamp="2025-11-07T16:57:01.025Z" hostname="MacBook-Air-Oleg.local" time="0.052">
<properties/>
<testcase name="findById_WhenDeliveryExists_ShouldReturnDelivery()" classname="com.example.service.DeliveryServiceTest" time="0.04"/>
<testcase name="create_WhenValidData_ShouldCreateDelivery()" classname="com.example.service.DeliveryServiceTest" time="0.001"/>
<testcase name="findById_WhenDeliveryExists_ShouldReturnDelivery()" classname="com.example.service.DeliveryServiceTest" time="0.043"/>
<testcase name="create_WhenValidData_ShouldCreateDelivery()" classname="com.example.service.DeliveryServiceTest" time="0.002"/>
<testcase name="delete_WhenDeliveryNotExists_ShouldReturnFalse()" classname="com.example.service.DeliveryServiceTest" time="0.001"/>
<testcase name="update_WhenDeliveryExists_ShouldUpdateDelivery()" classname="com.example.service.DeliveryServiceTest" time="0.001"/>
<testcase name="update_WhenDeliveryExists_ShouldUpdateDelivery()" classname="com.example.service.DeliveryServiceTest" time="0.002"/>
<testcase name="delete_WhenDeliveryExists_ShouldDeleteDelivery()" classname="com.example.service.DeliveryServiceTest" time="0.001"/>
<testcase name="findAll_ShouldReturnAllDeliveries()" classname="com.example.service.DeliveryServiceTest" time="0.001"/>
<testcase name="findAll_ShouldReturnAllDeliveries()" classname="com.example.service.DeliveryServiceTest" time="0.002"/>
<system-out><![CDATA[]]></system-out>
<system-err><![CDATA[]]></system-err>
</testsuite>

View File

@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="com.example.service.OrderServiceTest" tests="7" skipped="0" failures="0" errors="0" timestamp="2025-10-24T20:35:22.598Z" hostname="MacBook-Air-Oleg.local" time="0.048">
<testsuite name="com.example.service.OrderServiceTest" tests="9" skipped="0" failures="0" errors="0" timestamp="2025-11-07T16:57:01.079Z" hostname="MacBook-Air-Oleg.local" time="0.052">
<properties/>
<testcase name="create_WhenValidData_ShouldCreateOrder()" classname="com.example.service.OrderServiceTest" time="0.038"/>
<testcase name="create_WhenCustomerNotFound_ShouldThrowException()" classname="com.example.service.OrderServiceTest" time="0.003"/>
<testcase name="findById_WhenOrderExists_ShouldReturnOrder()" classname="com.example.service.OrderServiceTest" time="0.001"/>
<testcase name="findByCustomerId_ShouldReturnCustomerOrders()" classname="com.example.service.OrderServiceTest" time="0.002"/>
<testcase name="create_WhenCustomerNotFound_ShouldThrowException()" classname="com.example.service.OrderServiceTest" time="0.001"/>
<testcase name="findById_WhenOrderExists_ShouldReturnOrder()" classname="com.example.service.OrderServiceTest" time="0.002"/>
<testcase name="findAll_ShouldReturnAllOrders()" classname="com.example.service.OrderServiceTest" time="0.002"/>
<testcase name="delete_WhenOrderNotExists_ShouldReturnFalse()" classname="com.example.service.OrderServiceTest" time="0.001"/>
<testcase name="findByStatus_ShouldReturnOrdersByStatus()" classname="com.example.service.OrderServiceTest" time="0.002"/>
<testcase name="delete_WhenOrderExists_ShouldDeleteOrder()" classname="com.example.service.OrderServiceTest" time="0.001"/>
<testcase name="update_WhenOrderExists_ShouldUpdateOrder()" classname="com.example.service.OrderServiceTest" time="0.002"/>
<system-out><![CDATA[]]></system-out>

View File

@@ -0,0 +1,12 @@
Manifest-Version: 1.0
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.example.DemoApplication
Spring-Boot-Version: 3.5.5
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Build-Jdk-Spec: 21
Implementation-Title: demo
Implementation-Version: 0.0.1-SNAPSHOT

View File

@@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@@ -2,12 +2,12 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/assets/react.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ivanich Logistics Vite + React</title>
<title>Delivery Management System</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,885 @@
# Node.js
Node.js is an open-source, cross-platform JavaScript runtime environment.
For information on using Node.js, see the [Node.js website][].
The Node.js project uses an [open governance model](./GOVERNANCE.md). The
[OpenJS Foundation][] provides support for the project.
Contributors are expected to act in a collaborative manner to move
the project forward. We encourage the constructive exchange of contrary
opinions and compromise. The [TSC](./GOVERNANCE.md#technical-steering-committee)
reserves the right to limit or block contributors who repeatedly act in ways
that discourage, exhaust, or otherwise negatively affect other participants.
**This project has a [Code of Conduct][].**
## Table of contents
* [Support](#support)
* [Release types](#release-types)
* [Download](#download)
* [Current and LTS releases](#current-and-lts-releases)
* [Nightly releases](#nightly-releases)
* [API documentation](#api-documentation)
* [Verifying binaries](#verifying-binaries)
* [Building Node.js](#building-nodejs)
* [Security](#security)
* [Contributing to Node.js](#contributing-to-nodejs)
* [Current project team members](#current-project-team-members)
* [TSC (Technical Steering Committee)](#tsc-technical-steering-committee)
* [Collaborators](#collaborators)
* [Triagers](#triagers)
* [Release keys](#release-keys)
* [License](#license)
## Support
Looking for help? Check out the
[instructions for getting support](.github/SUPPORT.md).
## Release types
* **Current**: Under active development. Code for the Current release is in the
branch for its major version number (for example,
[v22.x](https://github.com/nodejs/node/tree/v22.x)). Node.js releases a new
major version every 6 months, allowing for breaking changes. This happens in
April and October every year. Releases appearing each October have a support
life of 8 months. Releases appearing each April convert to LTS (see below)
each October.
* **LTS**: Releases that receive Long Term Support, with a focus on stability
and security. Every even-numbered major version will become an LTS release.
LTS releases receive 12 months of _Active LTS_ support and a further 18 months
of _Maintenance_. LTS release lines have alphabetically-ordered code names,
beginning with v4 Argon. There are no breaking changes or feature additions,
except in some special circumstances.
* **Nightly**: Code from the Current branch built every 24-hours when there are
changes. Use with caution.
Current and LTS releases follow [semantic versioning](https://semver.org). A
member of the Release Team [signs](#release-keys) each Current and LTS release.
For more information, see the
[Release README](https://github.com/nodejs/Release#readme).
### Download
Binaries, installers, and source tarballs are available at
<https://nodejs.org/en/download/>.
#### Current and LTS releases
<https://nodejs.org/download/release/>
The [latest](https://nodejs.org/download/release/latest/) directory is an
alias for the latest Current release. The latest-_codename_ directory is an
alias for the latest release from an LTS line. For example, the
[latest-hydrogen](https://nodejs.org/download/release/latest-hydrogen/)
directory contains the latest Hydrogen (Node.js 18) release.
#### Nightly releases
<https://nodejs.org/download/nightly/>
Each directory name and filename contains a date (in UTC) and the commit
SHA at the HEAD of the release.
#### API documentation
Documentation for the latest Current release is at <https://nodejs.org/api/>.
Version-specific documentation is available in each release directory in the
_docs_ subdirectory. Version-specific documentation is also at
<https://nodejs.org/download/docs/>.
### Verifying binaries
Download directories contain a `SHASUMS256.txt` file with SHA checksums for the
files.
To download `SHASUMS256.txt` using `curl`:
```bash
curl -O https://nodejs.org/dist/vx.y.z/SHASUMS256.txt
```
To check that a downloaded file matches the checksum, run
it through `sha256sum` with a command such as:
```bash
grep node-vx.y.z.tar.gz SHASUMS256.txt | sha256sum -c -
```
For Current and LTS, the GPG detached signature of `SHASUMS256.txt` is in
`SHASUMS256.txt.sig`. You can use it with `gpg` to verify the integrity of
`SHASUMS256.txt`. You will first need to import
[the GPG keys of individuals authorized to create releases](#release-keys).
See [Release keys](#release-keys) for commands to import active release keys.
Next, download the `SHASUMS256.txt.sig` for the release:
```bash
curl -O https://nodejs.org/dist/vx.y.z/SHASUMS256.txt.sig
```
Then use `gpg --verify SHASUMS256.txt.sig SHASUMS256.txt` to verify
the file's signature.
## Building Node.js
See [BUILDING.md](BUILDING.md) for instructions on how to build Node.js from
source and a list of supported platforms.
## Security
For information on reporting security vulnerabilities in Node.js, see
[SECURITY.md](./SECURITY.md).
## Contributing to Node.js
* [Contributing to the project][]
* [Working Groups][]
* [Strategic initiatives][]
* [Technical values and prioritization][]
## Current project team members
For information about the governance of the Node.js project, see
[GOVERNANCE.md](./GOVERNANCE.md).
<!-- node-core-utils and find-inactive-tsc.mjs depend on the format of the TSC
list. If the format changes, those utilities need to be tested and
updated. -->
### TSC (Technical Steering Committee)
#### TSC voting members
<!--lint disable prohibited-strings-->
* [aduh95](https://github.com/aduh95) -
**Antoine du Hamel** <<duhamelantoine1995@gmail.com>> (he/him)
* [anonrig](https://github.com/anonrig) -
**Yagiz Nizipli** <<yagiz@nizipli.com>> (he/him)
* [benjamingr](https://github.com/benjamingr) -
**Benjamin Gruenbaum** <<benjamingr@gmail.com>>
* [BridgeAR](https://github.com/BridgeAR) -
**Ruben Bridgewater** <<ruben@bridgewater.de>> (he/him)
* [gireeshpunathil](https://github.com/gireeshpunathil) -
**Gireesh Punathil** <<gpunathi@in.ibm.com>> (he/him)
* [jasnell](https://github.com/jasnell) -
**James M Snell** <<jasnell@gmail.com>> (he/him)
* [joyeecheung](https://github.com/joyeecheung) -
**Joyee Cheung** <<joyeec9h3@gmail.com>> (she/her)
* [legendecas](https://github.com/legendecas) -
**Chengzhong Wu** <<legendecas@gmail.com>> (he/him)
* [marco-ippolito](https://github.com/marco-ippolito) -
**Marco Ippolito** <<marcoippolito54@gmail.com>> (he/him)
* [mcollina](https://github.com/mcollina) -
**Matteo Collina** <<matteo.collina@gmail.com>> (he/him)
* [mhdawson](https://github.com/mhdawson) -
**Michael Dawson** <<midawson@redhat.com>> (he/him)
* [MoLow](https://github.com/MoLow) -
**Moshe Atlow** <<moshe@atlow.co.il>> (he/him)
* [RafaelGSS](https://github.com/RafaelGSS) -
**Rafael Gonzaga** <<rafael.nunu@hotmail.com>> (he/him)
* [richardlau](https://github.com/richardlau) -
**Richard Lau** <<rlau@redhat.com>>
* [ronag](https://github.com/ronag) -
**Robert Nagy** <<ronagy@icloud.com>>
* [ruyadorno](https://github.com/ruyadorno) -
**Ruy Adorno** <<ruy@vlt.sh>> (he/him)
* [ShogunPanda](https://github.com/ShogunPanda) -
**Paolo Insogna** <<paolo@cowtech.it>> (he/him)
* [targos](https://github.com/targos) -
**Michaël Zasso** <<targos@protonmail.com>> (he/him)
* [tniessen](https://github.com/tniessen) -
**Tobias Nießen** <<tniessen@tnie.de>> (he/him)
#### TSC regular members
* [apapirovski](https://github.com/apapirovski) -
**Anatoli Papirovski** <<apapirovski@mac.com>> (he/him)
* [BethGriggs](https://github.com/BethGriggs) -
**Beth Griggs** <<bethanyngriggs@gmail.com>> (she/her)
* [bnoordhuis](https://github.com/bnoordhuis) -
**Ben Noordhuis** <<info@bnoordhuis.nl>>
* [cjihrig](https://github.com/cjihrig) -
**Colin Ihrig** <<cjihrig@gmail.com>> (he/him)
* [codebytere](https://github.com/codebytere) -
**Shelley Vohr** <<shelley.vohr@gmail.com>> (she/her)
* [GeoffreyBooth](https://github.com/GeoffreyBooth) -
**Geoffrey Booth** <<webadmin@geoffreybooth.com>> (he/him)
* [Trott](https://github.com/Trott) -
**Rich Trott** <<rtrott@gmail.com>> (he/him)
<details>
<summary>TSC emeriti members</summary>
#### TSC emeriti members
* [addaleax](https://github.com/addaleax) -
**Anna Henningsen** <<anna@addaleax.net>> (she/her)
* [ChALkeR](https://github.com/ChALkeR) -
**Сковорода Никита Андреевич** <<chalkerx@gmail.com>> (he/him)
* [chrisdickinson](https://github.com/chrisdickinson) -
**Chris Dickinson** <<christopher.s.dickinson@gmail.com>>
* [danbev](https://github.com/danbev) -
**Daniel Bevenius** <<daniel.bevenius@gmail.com>> (he/him)
* [danielleadams](https://github.com/danielleadams) -
**Danielle Adams** <<adamzdanielle@gmail.com>> (she/her)
* [evanlucas](https://github.com/evanlucas) -
**Evan Lucas** <<evanlucas@me.com>> (he/him)
* [fhinkel](https://github.com/fhinkel) -
**Franziska Hinkelmann** <<franziska.hinkelmann@gmail.com>> (she/her)
* [Fishrock123](https://github.com/Fishrock123) -
**Jeremiah Senkpiel** <<fishrock123@rocketmail.com>> (he/they)
* [gabrielschulhof](https://github.com/gabrielschulhof) -
**Gabriel Schulhof** <<gabrielschulhof@gmail.com>>
* [gibfahn](https://github.com/gibfahn) -
**Gibson Fahnestock** <<gibfahn@gmail.com>> (he/him)
* [indutny](https://github.com/indutny) -
**Fedor Indutny** <<fedor@indutny.com>>
* [isaacs](https://github.com/isaacs) -
**Isaac Z. Schlueter** <<i@izs.me>>
* [joshgav](https://github.com/joshgav) -
**Josh Gavant** <<josh.gavant@outlook.com>>
* [mmarchini](https://github.com/mmarchini) -
**Mary Marchini** <<oss@mmarchini.me>> (she/her)
* [mscdex](https://github.com/mscdex) -
**Brian White** <<mscdex@mscdex.net>>
* [MylesBorins](https://github.com/MylesBorins) -
**Myles Borins** <<myles.borins@gmail.com>> (he/him)
* [nebrius](https://github.com/nebrius) -
**Bryan Hughes** <<bryan@nebri.us>>
* [ofrobots](https://github.com/ofrobots) -
**Ali Ijaz Sheikh** <<ofrobots@google.com>> (he/him)
* [orangemocha](https://github.com/orangemocha) -
**Alexis Campailla** <<orangemocha@nodejs.org>>
* [piscisaureus](https://github.com/piscisaureus) -
**Bert Belder** <<bertbelder@gmail.com>>
* [RaisinTen](https://github.com/RaisinTen) -
**Darshan Sen** <<raisinten@gmail.com>> (he/him)
* [rvagg](https://github.com/rvagg) -
**Rod Vagg** <<r@va.gg>>
* [sam-github](https://github.com/sam-github) -
**Sam Roberts** <<vieuxtech@gmail.com>>
* [shigeki](https://github.com/shigeki) -
**Shigeki Ohtsu** <<ohtsu@ohtsu.org>> (he/him)
* [thefourtheye](https://github.com/thefourtheye) -
**Sakthipriyan Vairamani** <<thechargingvolcano@gmail.com>> (he/him)
* [TimothyGu](https://github.com/TimothyGu) -
**Tiancheng "Timothy" Gu** <<timothygu99@gmail.com>> (he/him)
* [trevnorris](https://github.com/trevnorris) -
**Trevor Norris** <<trev.norris@gmail.com>>
</details>
<!-- node-core-utils and find-inactive-collaborators.mjs depend on the format
of the collaborator list. If the format changes, those utilities need to be
tested and updated. -->
### Collaborators
* [addaleax](https://github.com/addaleax) -
**Anna Henningsen** <<anna@addaleax.net>> (she/her)
* [aduh95](https://github.com/aduh95) -
**Antoine du Hamel** <<duhamelantoine1995@gmail.com>> (he/him) - [Support me](https://github.com/sponsors/aduh95)
* [anonrig](https://github.com/anonrig) -
**Yagiz Nizipli** <<yagiz@nizipli.com>> (he/him) - [Support me](https://github.com/sponsors/anonrig)
* [apapirovski](https://github.com/apapirovski) -
**Anatoli Papirovski** <<apapirovski@mac.com>> (he/him)
* [atlowChemi](https://github.com/atlowChemi) -
**Chemi Atlow** <<chemi@atlow.co.il>> (he/him)
* [Ayase-252](https://github.com/Ayase-252) -
**Qingyu Deng** <<i@ayase-lab.com>>
* [bengl](https://github.com/bengl) -
**Bryan English** <<bryan@bryanenglish.com>> (he/him)
* [benjamingr](https://github.com/benjamingr) -
**Benjamin Gruenbaum** <<benjamingr@gmail.com>>
* [BethGriggs](https://github.com/BethGriggs) -
**Beth Griggs** <<bethanyngriggs@gmail.com>> (she/her)
* [bnb](https://github.com/bnb) -
**Tierney Cyren** <<hello@bnb.im>> (they/them)
* [bnoordhuis](https://github.com/bnoordhuis) -
**Ben Noordhuis** <<info@bnoordhuis.nl>>
* [BridgeAR](https://github.com/BridgeAR) -
**Ruben Bridgewater** <<ruben@bridgewater.de>> (he/him)
* [cclauss](https://github.com/cclauss) -
**Christian Clauss** <<cclauss@me.com>> (he/him)
* [cjihrig](https://github.com/cjihrig) -
**Colin Ihrig** <<cjihrig@gmail.com>> (he/him)
* [codebytere](https://github.com/codebytere) -
**Shelley Vohr** <<shelley.vohr@gmail.com>> (she/her)
* [cola119](https://github.com/cola119) -
**Kohei Ueno** <<kohei.ueno119@gmail.com>> (he/him)
* [daeyeon](https://github.com/daeyeon) -
**Daeyeon Jeong** <<daeyeon.dev@gmail.com>> (he/him)
* [danielleadams](https://github.com/danielleadams) -
**Danielle Adams** <<adamzdanielle@gmail.com>> (she/her)
* [debadree25](https://github.com/debadree25) -
**Debadree Chatterjee** <<debadree333@gmail.com>> (he/him)
* [deokjinkim](https://github.com/deokjinkim) -
**Deokjin Kim** <<deokjin81.kim@gmail.com>> (he/him)
* [edsadr](https://github.com/edsadr) -
**Adrian Estrada** <<edsadr@gmail.com>> (he/him)
* [ErickWendel](https://github.com/ErickWendel) -
**Erick Wendel** <<erick.workspace@gmail.com>> (he/him)
* [Ethan-Arrowood](https://github.com/Ethan-Arrowood) -
**Ethan Arrowood** <<ethan@arrowood.dev>> (he/him)
* [F3n67u](https://github.com/F3n67u) -
**Feng Yu** <<F3n67u@outlook.com>> (he/him)
* [fhinkel](https://github.com/fhinkel) -
**Franziska Hinkelmann** <<franziska.hinkelmann@gmail.com>> (she/her)
* [Flarna](https://github.com/Flarna) -
**Gerhard Stöbich** <<deb2001-github@yahoo.de>> (he/they)
* [gabrielschulhof](https://github.com/gabrielschulhof) -
**Gabriel Schulhof** <<gabrielschulhof@gmail.com>>
* [gengjiawen](https://github.com/gengjiawen) -
**Jiawen Geng** <<technicalcute@gmail.com>>
* [GeoffreyBooth](https://github.com/GeoffreyBooth) -
**Geoffrey Booth** <<webadmin@geoffreybooth.com>> (he/him)
* [gireeshpunathil](https://github.com/gireeshpunathil) -
**Gireesh Punathil** <<gpunathi@in.ibm.com>> (he/him)
* [guybedford](https://github.com/guybedford) -
**Guy Bedford** <<guybedford@gmail.com>> (he/him)
* [H4ad](https://github.com/H4ad) -
**Vinícius Lourenço Claro Cardoso** <<contact@viniciusl.com.br>> (he/him)
* [HarshithaKP](https://github.com/HarshithaKP) -
**Harshitha K P** <<harshitha014@gmail.com>> (she/her)
* [himself65](https://github.com/himself65) -
**Zeyu "Alex" Yang** <<himself65@outlook.com>> (he/him)
* [jakecastelli](https://github.com/jakecastelli) -
**Jake Yuesong Li** <<jake.yuesong@gmail.com>> (he/him)
* [JakobJingleheimer](https://github.com/JakobJingleheimer) -
**Jacob Smith** <<jacob@frende.me>> (he/him)
* [jasnell](https://github.com/jasnell) -
**James M Snell** <<jasnell@gmail.com>> (he/him)
* [jkrems](https://github.com/jkrems) -
**Jan Krems** <<jan.krems@gmail.com>> (he/him)
* [joesepi](https://github.com/joesepi) -
**Joe Sepi** <<sepi@joesepi.com>> (he/him)
* [joyeecheung](https://github.com/joyeecheung) -
**Joyee Cheung** <<joyeec9h3@gmail.com>> (she/her)
* [juanarbol](https://github.com/juanarbol) -
**Juan José Arboleda** <<soyjuanarbol@gmail.com>> (he/him)
* [JungMinu](https://github.com/JungMinu) -
**Minwoo Jung** <<nodecorelab@gmail.com>> (he/him)
* [KhafraDev](https://github.com/KhafraDev) -
**Matthew Aitken** <<maitken033380023@gmail.com>> (he/him)
* [kvakil](https://github.com/kvakil) -
**Keyhan Vakil** <<kvakil@sylph.kvakil.me>>
* [legendecas](https://github.com/legendecas) -
**Chengzhong Wu** <<legendecas@gmail.com>> (he/him)
* [lemire](https://github.com/lemire) -
**Daniel Lemire** <<daniel@lemire.me>>
* [Linkgoron](https://github.com/Linkgoron) -
**Nitzan Uziely** <<linkgoron@gmail.com>>
* [LiviaMedeiros](https://github.com/LiviaMedeiros) -
**LiviaMedeiros** <<livia@cirno.name>>
* [lpinca](https://github.com/lpinca) -
**Luigi Pinca** <<luigipinca@gmail.com>> (he/him)
* [lukekarrys](https://github.com/lukekarrys) -
**Luke Karrys** <<luke@lukekarrys.com>> (he/him)
* [Lxxyx](https://github.com/Lxxyx) -
**Zijian Liu** <<lxxyxzj@gmail.com>> (he/him)
* [marco-ippolito](https://github.com/marco-ippolito) -
**Marco Ippolito** <<marcoippolito54@gmail.com>> (he/him) - [Support me](https://github.com/sponsors/marco-ippolito)
* [marsonya](https://github.com/marsonya) -
**Akhil Marsonya** <<akhil.marsonya27@gmail.com>> (he/him)
* [MattiasBuelens](https://github.com/MattiasBuelens) -
**Mattias Buelens** <<mattias@buelens.com>> (he/him)
* [mcollina](https://github.com/mcollina) -
**Matteo Collina** <<matteo.collina@gmail.com>> (he/him) - [Support me](https://github.com/sponsors/mcollina)
* [meixg](https://github.com/meixg) -
**Xuguang Mei** <<meixuguang@gmail.com>> (he/him)
* [mhdawson](https://github.com/mhdawson) -
**Michael Dawson** <<midawson@redhat.com>> (he/him)
* [mildsunrise](https://github.com/mildsunrise) -
**Alba Mendez** <<me@alba.sh>> (she/her)
* [MoLow](https://github.com/MoLow) -
**Moshe Atlow** <<moshe@atlow.co.il>> (he/him)
* [MrJithil](https://github.com/MrJithil) -
**Jithil P Ponnan** <<jithil@outlook.com>> (he/him)
* [ovflowd](https://github.com/ovflowd) -
**Claudio Wunder** <<cwunder@gnome.org>> (he/they)
* [panva](https://github.com/panva) -
**Filip Skokan** <<panva.ip@gmail.com>> (he/him)
* [pimterry](https://github.com/pimterry) -
**Tim Perry** <<pimterry@gmail.com>> (he/him)
* [Qard](https://github.com/Qard) -
**Stephen Belanger** <<admin@stephenbelanger.com>> (he/him)
* [RafaelGSS](https://github.com/RafaelGSS) -
**Rafael Gonzaga** <<rafael.nunu@hotmail.com>> (he/him)
* [richardlau](https://github.com/richardlau) -
**Richard Lau** <<rlau@redhat.com>>
* [rluvaton](https://github.com/rluvaton) -
**Raz Luvaton** <<rluvaton@gmail.com>> (he/him)
* [ronag](https://github.com/ronag) -
**Robert Nagy** <<ronagy@icloud.com>>
* [ruyadorno](https://github.com/ruyadorno) -
**Ruy Adorno** <<ruy@vlt.sh>> (he/him)
* [santigimeno](https://github.com/santigimeno) -
**Santiago Gimeno** <<santiago.gimeno@gmail.com>>
* [ShogunPanda](https://github.com/ShogunPanda) -
**Paolo Insogna** <<paolo@cowtech.it>> (he/him)
* [srl295](https://github.com/srl295) -
**Steven R Loomis** <<srl295@gmail.com>>
* [StefanStojanovic](https://github.com/StefanStojanovic) -
**Stefan Stojanovic** <<stefan.stojanovic@janeasystems.com>> (he/him)
* [sxa](https://github.com/sxa) -
**Stewart X Addison** <<sxa@redhat.com>> (he/him)
* [targos](https://github.com/targos) -
**Michaël Zasso** <<targos@protonmail.com>> (he/him)
* [theanarkh](https://github.com/theanarkh) -
**theanarkh** <<theratliter@gmail.com>> (he/him)
* [tniessen](https://github.com/tniessen) -
**Tobias Nießen** <<tniessen@tnie.de>> (he/him)
* [trivikr](https://github.com/trivikr) -
**Trivikram Kamat** <<trivikr.dev@gmail.com>>
* [Trott](https://github.com/Trott) -
**Rich Trott** <<rtrott@gmail.com>> (he/him)
* [UlisesGascon](https://github.com/UlisesGascon) -
**Ulises Gascón** <<ulisesgascongonzalez@gmail.com>> (he/him)
* [vmoroz](https://github.com/vmoroz) -
**Vladimir Morozov** <<vmorozov@microsoft.com>> (he/him)
* [VoltrexKeyva](https://github.com/VoltrexKeyva) -
**Mohammed Keyvanzadeh** <<mohammadkeyvanzade94@gmail.com>> (he/him)
* [watilde](https://github.com/watilde) -
**Daijiro Wachi** <<daijiro.wachi@gmail.com>> (he/him)
* [zcbenz](https://github.com/zcbenz) -
**Cheng Zhao** <<zcbenz@gmail.com>> (he/him)
* [ZYSzys](https://github.com/ZYSzys) -
**Yongsheng Zhang** <<zyszys98@gmail.com>> (he/him)
<details>
<summary>Emeriti</summary>
<!-- find-inactive-collaborators.mjs depends on the format of the emeriti list.
If the format changes, those utilities need to be tested and updated. -->
### Collaborator emeriti
* [ak239](https://github.com/ak239) -
**Aleksei Koziatinskii** <<ak239spb@gmail.com>>
* [andrasq](https://github.com/andrasq) -
**Andras** <<andras@kinvey.com>>
* [AndreasMadsen](https://github.com/AndreasMadsen) -
**Andreas Madsen** <<amwebdk@gmail.com>> (he/him)
* [AnnaMag](https://github.com/AnnaMag) -
**Anna M. Kedzierska** <<anna.m.kedzierska@gmail.com>>
* [antsmartian](https://github.com/antsmartian) -
**Anto Aravinth** <<anto.aravinth.cse@gmail.com>> (he/him)
* [aqrln](https://github.com/aqrln) -
**Alexey Orlenko** <<eaglexrlnk@gmail.com>> (he/him)
* [AshCripps](https://github.com/AshCripps) -
**Ash Cripps** <<email@ashleycripps.co.uk>>
* [bcoe](https://github.com/bcoe) -
**Ben Coe** <<bencoe@gmail.com>> (he/him)
* [bmeck](https://github.com/bmeck) -
**Bradley Farias** <<bradley.meck@gmail.com>>
* [bmeurer](https://github.com/bmeurer) -
**Benedikt Meurer** <<benedikt.meurer@gmail.com>>
* [boneskull](https://github.com/boneskull) -
**Christopher Hiller** <<boneskull@boneskull.com>> (he/him)
* [brendanashworth](https://github.com/brendanashworth) -
**Brendan Ashworth** <<brendan.ashworth@me.com>>
* [bzoz](https://github.com/bzoz) -
**Bartosz Sosnowski** <<bartosz@janeasystems.com>>
* [calvinmetcalf](https://github.com/calvinmetcalf) -
**Calvin Metcalf** <<calvin.metcalf@gmail.com>>
* [ChALkeR](https://github.com/ChALkeR) -
**Сковорода Никита Андреевич** <<chalkerx@gmail.com>> (he/him)
* [chrisdickinson](https://github.com/chrisdickinson) -
**Chris Dickinson** <<christopher.s.dickinson@gmail.com>>
* [claudiorodriguez](https://github.com/claudiorodriguez) -
**Claudio Rodriguez** <<cjrodr@yahoo.com>>
* [danbev](https://github.com/danbev) -
**Daniel Bevenius** <<daniel.bevenius@gmail.com>> (he/him)
* [DavidCai1993](https://github.com/DavidCai1993) -
**David Cai** <<davidcai1993@yahoo.com>> (he/him)
* [davisjam](https://github.com/davisjam) -
**Jamie Davis** <<davisjam@vt.edu>> (he/him)
* [devnexen](https://github.com/devnexen) -
**David Carlier** <<devnexen@gmail.com>>
* [devsnek](https://github.com/devsnek) -
**Gus Caplan** <<me@gus.host>> (they/them)
* [digitalinfinity](https://github.com/digitalinfinity) -
**Hitesh Kanwathirtha** <<digitalinfinity@gmail.com>> (he/him)
* [dmabupt](https://github.com/dmabupt) -
**Xu Meng** <<dmabupt@gmail.com>> (he/him)
* [dnlup](https://github.com/dnlup)
**dnlup** <<dnlup.dev@gmail.com>>
* [eljefedelrodeodeljefe](https://github.com/eljefedelrodeodeljefe) -
**Robert Jefe Lindstaedt** <<robert.lindstaedt@gmail.com>>
* [estliberitas](https://github.com/estliberitas) -
**Alexander Makarenko** <<estliberitas@gmail.com>>
* [eugeneo](https://github.com/eugeneo) -
**Eugene Ostroukhov** <<eostroukhov@google.com>>
* [evanlucas](https://github.com/evanlucas) -
**Evan Lucas** <<evanlucas@me.com>> (he/him)
* [firedfox](https://github.com/firedfox) -
**Daniel Wang** <<wangyang0123@gmail.com>>
* [Fishrock123](https://github.com/Fishrock123) -
**Jeremiah Senkpiel** <<fishrock123@rocketmail.com>> (he/they)
* [gdams](https://github.com/gdams) -
**George Adams** <<gadams@microsoft.com>> (he/him)
* [geek](https://github.com/geek) -
**Wyatt Preul** <<wpreul@gmail.com>>
* [gibfahn](https://github.com/gibfahn) -
**Gibson Fahnestock** <<gibfahn@gmail.com>> (he/him)
* [glentiki](https://github.com/glentiki) -
**Glen Keane** <<glenkeane.94@gmail.com>> (he/him)
* [hashseed](https://github.com/hashseed) -
**Yang Guo** <<yangguo@chromium.org>> (he/him)
* [hiroppy](https://github.com/hiroppy) -
**Yuta Hiroto** <<hello@hiroppy.me>> (he/him)
* [iansu](https://github.com/iansu) -
**Ian Sutherland** <<ian@iansutherland.ca>>
* [iarna](https://github.com/iarna) -
**Rebecca Turner** <<me@re-becca.org>>
* [imran-iq](https://github.com/imran-iq) -
**Imran Iqbal** <<imran@imraniqbal.org>>
* [imyller](https://github.com/imyller) -
**Ilkka Myller** <<ilkka.myller@nodefield.com>>
* [indutny](https://github.com/indutny) -
**Fedor Indutny** <<fedor@indutny.com>>
* [isaacs](https://github.com/isaacs) -
**Isaac Z. Schlueter** <<i@izs.me>>
* [italoacasas](https://github.com/italoacasas) -
**Italo A. Casas** <<me@italoacasas.com>> (he/him)
* [JacksonTian](https://github.com/JacksonTian) -
**Jackson Tian** <<shyvo1987@gmail.com>>
* [jasongin](https://github.com/jasongin) -
**Jason Ginchereau** <<jasongin@microsoft.com>>
* [jbergstroem](https://github.com/jbergstroem) -
**Johan Bergström** <<bugs@bergstroem.nu>>
* [jdalton](https://github.com/jdalton) -
**John-David Dalton** <<john.david.dalton@gmail.com>>
* [jhamhader](https://github.com/jhamhader) -
**Yuval Brik** <<yuval@brik.org.il>>
* [joaocgreis](https://github.com/joaocgreis) -
**João Reis** <<reis@janeasystems.com>>
* [joshgav](https://github.com/joshgav) -
**Josh Gavant** <<josh.gavant@outlook.com>>
* [julianduque](https://github.com/julianduque) -
**Julian Duque** <<julianduquej@gmail.com>> (he/him)
* [kfarnung](https://github.com/kfarnung) -
**Kyle Farnung** <<kfarnung@microsoft.com>> (he/him)
* [kunalspathak](https://github.com/kunalspathak) -
**Kunal Pathak** <<kunal.pathak@microsoft.com>>
* [kuriyosh](https://github.com/kuriyosh) -
**Yoshiki Kurihara** <<yosyos0306@gmail.com>> (he/him)
* [lance](https://github.com/lance) -
**Lance Ball** <<lball@redhat.com>> (he/him)
* [Leko](https://github.com/Leko) -
**Shingo Inoue** <<leko.noor@gmail.com>> (he/him)
* [lucamaraschi](https://github.com/lucamaraschi) -
**Luca Maraschi** <<luca.maraschi@gmail.com>> (he/him)
* [lundibundi](https://github.com/lundibundi) -
**Denys Otrishko** <<shishugi@gmail.com>> (he/him)
* [lxe](https://github.com/lxe) -
**Aleksey Smolenchuk** <<lxe@lxe.co>>
* [maclover7](https://github.com/maclover7) -
**Jon Moss** <<me@jonathanmoss.me>> (he/him)
* [mafintosh](https://github.com/mafintosh) -
**Mathias Buus** <<mathiasbuus@gmail.com>> (he/him)
* [matthewloring](https://github.com/matthewloring) -
**Matthew Loring** <<mattloring@google.com>>
* [Mesteery](https://github.com/Mesteery) -
**Mestery** <<mestery@protonmail.com>> (he/him)
* [micnic](https://github.com/micnic) -
**Nicu Micleușanu** <<micnic90@gmail.com>> (he/him)
* [mikeal](https://github.com/mikeal) -
**Mikeal Rogers** <<mikeal.rogers@gmail.com>>
* [miladfarca](https://github.com/miladfarca) -
**Milad Fa** <<mfarazma@redhat.com>> (he/him)
* [misterdjules](https://github.com/misterdjules) -
**Julien Gilli** <<jgilli@netflix.com>>
* [mmarchini](https://github.com/mmarchini) -
**Mary Marchini** <<oss@mmarchini.me>> (she/her)
* [monsanto](https://github.com/monsanto) -
**Christopher Monsanto** <<chris@monsan.to>>
* [MoonBall](https://github.com/MoonBall) -
**Chen Gang** <<gangc.cxy@foxmail.com>>
* [mscdex](https://github.com/mscdex) -
**Brian White** <<mscdex@mscdex.net>>
* [MylesBorins](https://github.com/MylesBorins) -
**Myles Borins** <<myles.borins@gmail.com>> (he/him)
* [not-an-aardvark](https://github.com/not-an-aardvark) -
**Teddy Katz** <<teddy.katz@gmail.com>> (he/him)
* [ofrobots](https://github.com/ofrobots) -
**Ali Ijaz Sheikh** <<ofrobots@google.com>> (he/him)
* [Olegas](https://github.com/Olegas) -
**Oleg Elifantiev** <<oleg@elifantiev.ru>>
* [orangemocha](https://github.com/orangemocha) -
**Alexis Campailla** <<orangemocha@nodejs.org>>
* [othiym23](https://github.com/othiym23) -
**Forrest L Norvell** <<ogd@aoaioxxysz.net>> (they/them/themself)
* [oyyd](https://github.com/oyyd) -
**Ouyang Yadong** <<oyydoibh@gmail.com>> (he/him)
* [petkaantonov](https://github.com/petkaantonov) -
**Petka Antonov** <<petka_antonov@hotmail.com>>
* [phillipj](https://github.com/phillipj) -
**Phillip Johnsen** <<johphi@gmail.com>>
* [piscisaureus](https://github.com/piscisaureus) -
**Bert Belder** <<bertbelder@gmail.com>>
* [pmq20](https://github.com/pmq20) -
**Minqi Pan** <<pmq2001@gmail.com>>
* [PoojaDurgad](https://github.com/PoojaDurgad) -
**Pooja D P** <<Pooja.D.P@ibm.com>> (she/her)
* [princejwesley](https://github.com/princejwesley) -
**Prince John Wesley** <<princejohnwesley@gmail.com>>
* [psmarshall](https://github.com/psmarshall) -
**Peter Marshall** <<petermarshall@chromium.org>> (he/him)
* [puzpuzpuz](https://github.com/puzpuzpuz) -
**Andrey Pechkurov** <<apechkurov@gmail.com>> (he/him)
* [RaisinTen](https://github.com/RaisinTen) -
**Darshan Sen** <<raisinten@gmail.com>> (he/him)
* [refack](https://github.com/refack) -
**Refael Ackermann (רפאל פלחי)** <<refack@gmail.com>> (he/him/הוא/אתה)
* [rexagod](https://github.com/rexagod) -
**Pranshu Srivastava** <<rexagod@gmail.com>> (he/him)
* [rickyes](https://github.com/rickyes) -
**Ricky Zhou** <<0x19951125@gmail.com>> (he/him)
* [rlidwka](https://github.com/rlidwka) -
**Alex Kocharin** <<alex@kocharin.ru>>
* [rmg](https://github.com/rmg) -
**Ryan Graham** <<r.m.graham@gmail.com>>
* [robertkowalski](https://github.com/robertkowalski) -
**Robert Kowalski** <<rok@kowalski.gd>>
* [romankl](https://github.com/romankl) -
**Roman Klauke** <<romaaan.git@gmail.com>>
* [ronkorving](https://github.com/ronkorving) -
**Ron Korving** <<ron@ronkorving.nl>>
* [RReverser](https://github.com/RReverser) -
**Ingvar Stepanyan** <<me@rreverser.com>>
* [rubys](https://github.com/rubys) -
**Sam Ruby** <<rubys@intertwingly.net>>
* [rvagg](https://github.com/rvagg) -
**Rod Vagg** <<rod@vagg.org>>
* [ryzokuken](https://github.com/ryzokuken) -
**Ujjwal Sharma** <<ryzokuken@disroot.org>> (he/him)
* [saghul](https://github.com/saghul) -
**Saúl Ibarra Corretgé** <<s@saghul.net>>
* [sam-github](https://github.com/sam-github) -
**Sam Roberts** <<vieuxtech@gmail.com>>
* [sebdeckers](https://github.com/sebdeckers) -
**Sebastiaan Deckers** <<sebdeckers83@gmail.com>>
* [seishun](https://github.com/seishun) -
**Nikolai Vavilov** <<vvnicholas@gmail.com>>
* [shigeki](https://github.com/shigeki) -
**Shigeki Ohtsu** <<ohtsu@ohtsu.org>> (he/him)
* [shisama](https://github.com/shisama) -
**Masashi Hirano** <<shisama07@gmail.com>> (he/him)
* [silverwind](https://github.com/silverwind) -
**Roman Reiss** <<me@silverwind.io>>
* [starkwang](https://github.com/starkwang) -
**Weijia Wang** <<starkwang@126.com>>
* [stefanmb](https://github.com/stefanmb) -
**Stefan Budeanu** <<stefan@budeanu.com>>
* [tellnes](https://github.com/tellnes) -
**Christian Tellnes** <<christian@tellnes.no>>
* [thefourtheye](https://github.com/thefourtheye) -
**Sakthipriyan Vairamani** <<thechargingvolcano@gmail.com>> (he/him)
* [thlorenz](https://github.com/thlorenz) -
**Thorsten Lorenz** <<thlorenz@gmx.de>>
* [TimothyGu](https://github.com/TimothyGu) -
**Tiancheng "Timothy" Gu** <<timothygu99@gmail.com>> (he/him)
* [trevnorris](https://github.com/trevnorris) -
**Trevor Norris** <<trev.norris@gmail.com>>
* [tunniclm](https://github.com/tunniclm) -
**Mike Tunnicliffe** <<m.j.tunnicliffe@gmail.com>>
* [vdeturckheim](https://github.com/vdeturckheim) -
**Vladimir de Turckheim** <<vlad2t@hotmail.com>> (he/him)
* [vkurchatkin](https://github.com/vkurchatkin) -
**Vladimir Kurchatkin** <<vladimir.kurchatkin@gmail.com>>
* [vsemozhetbyt](https://github.com/vsemozhetbyt) -
**Vse Mozhet Byt** <<vsemozhetbyt@gmail.com>> (he/him)
* [watson](https://github.com/watson) -
**Thomas Watson** <<w@tson.dk>>
* [whitlockjc](https://github.com/whitlockjc) -
**Jeremy Whitlock** <<jwhitlock@apache.org>>
* [XadillaX](https://github.com/XadillaX) -
**Khaidi Chu** <<i@2333.moe>> (he/him)
* [yashLadha](https://github.com/yashLadha) -
**Yash Ladha** <<yash@yashladha.in>> (he/him)
* [yhwang](https://github.com/yhwang) -
**Yihong Wang** <<yh.wang@ibm.com>>
* [yorkie](https://github.com/yorkie) -
**Yorkie Liu** <<yorkiefixer@gmail.com>>
* [yosuke-furukawa](https://github.com/yosuke-furukawa) -
**Yosuke Furukawa** <<yosuke.furukawa@gmail.com>>
</details>
<!--lint enable prohibited-strings-->
Collaborators follow the [Collaborator Guide](./doc/contributing/collaborator-guide.md) in
maintaining the Node.js project.
### Triagers
* [atlowChemi](https://github.com/atlowChemi) -
**Chemi Atlow** <<chemi@atlow.co.il>> (he/him)
* [Ayase-252](https://github.com/Ayase-252) -
**Qingyu Deng** <<i@ayase-lab.com>>
* [bmuenzenmeyer](https://github.com/bmuenzenmeyer) -
**Brian Muenzenmeyer** <<brian.muenzenmeyer@gmail.com>> (he/him)
* [CanadaHonk](https://github.com/CanadaHonk) -
**Oliver Medhurst** <<honk@goose.icu>> (they/them)
* [daeyeon](https://github.com/daeyeon) -
**Daeyeon Jeong** <<daeyeon.dev@gmail.com>> (he/him)
* [F3n67u](https://github.com/F3n67u) -
**Feng Yu** <<F3n67u@outlook.com>> (he/him)
* [gireeshpunathil](https://github.com/gireeshpunathil) -
**Gireesh Punathil** <<gpunathi@in.ibm.com>> (he/him)
* [iam-frankqiu](https://github.com/iam-frankqiu) -
**Frank Qiu** <<iam.frankqiu@gmail.com>> (he/him)
* [KevinEady](https://github.com/KevinEady) -
**Kevin Eady** <<kevin.c.eady@gmail.com>> (he/him)
* [kvakil](https://github.com/kvakil) -
**Keyhan Vakil** <<kvakil@sylph.kvakil.me>>
* [marsonya](https://github.com/marsonya) -
**Akhil Marsonya** <<akhil.marsonya27@gmail.com>> (he/him)
* [meixg](https://github.com/meixg) -
**Xuguang Mei** <<meixuguang@gmail.com>> (he/him)
* [mertcanaltin](https://github.com/mertcanaltin) -
**Mert Can Altin** <<mertgold60@gmail.com>>
* [preveen-stack](https://github.com/preveen-stack) -
**Preveen Padmanabhan** <<wide4head@gmail.com>> (he/him)
* [RedYetiDev](https://github.com/redyetidev) -
**Aviv Keller** <<redyetidev@gmail.com>> (they/them)
* [VoltrexKeyva](https://github.com/VoltrexKeyva) -
**Mohammed Keyvanzadeh** <<mohammadkeyvanzade94@gmail.com>> (he/him)
Triagers follow the [Triage Guide](./doc/contributing/issues.md#triaging-a-bug-report) when
responding to new issues.
### Release keys
Primary GPG keys for Node.js Releasers (some Releasers sign with subkeys):
* **Beth Griggs** <<bethanyngriggs@gmail.com>>
`4ED778F539E3634C779C87C6D7062848A1AB005C`
* **Bryan English** <<bryan@bryanenglish.com>>
`141F07595B7B3FFE74309A937405533BE57C7D57`
* **Danielle Adams** <<adamzdanielle@gmail.com>>
`74F12602B6F1C4E913FAA37AD3A89613643B6201`
* **Juan José Arboleda** <<soyjuanarbol@gmail.com>>
`DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7`
* **Marco Ippolito** <<marcoippolito54@gmail.com>>
`CC68F5A3106FF448322E48ED27F5E38D5B0A215F`
* **Michaël Zasso** <<targos@protonmail.com>>
`8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600`
* **Rafael Gonzaga** <<rafael.nunu@hotmail.com>>
`890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4`
* **Richard Lau** <<rlau@redhat.com>>
`C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C`
* **Ruy Adorno** <<ruyadorno@hotmail.com>>
`108F52B48DB57BB0CC439B2997B01419BD92F80A`
* **Ulises Gascón** <<ulisesgascongonzalez@gmail.com>>
`A363A499291CBBC940DD62E41F10027AF002F8B0`
To import the full set of trusted release keys (including subkeys possibly used
to sign releases):
```bash
gpg --keyserver hkps://keys.openpgp.org --recv-keys 4ED778F539E3634C779C87C6D7062848A1AB005C # Beth Griggs
gpg --keyserver hkps://keys.openpgp.org --recv-keys 141F07595B7B3FFE74309A937405533BE57C7D57 # Bryan English
gpg --keyserver hkps://keys.openpgp.org --recv-keys 74F12602B6F1C4E913FAA37AD3A89613643B6201 # Danielle Adams
gpg --keyserver hkps://keys.openpgp.org --recv-keys DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 # Juan José Arboleda
gpg --keyserver hkps://keys.openpgp.org --recv-keys CC68F5A3106FF448322E48ED27F5E38D5B0A215F # Marco Ippolito
gpg --keyserver hkps://keys.openpgp.org --recv-keys 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 # Michaël Zasso
gpg --keyserver hkps://keys.openpgp.org --recv-keys 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 # Rafael Gonzaga
gpg --keyserver hkps://keys.openpgp.org --recv-keys C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C # Richard Lau
gpg --keyserver hkps://keys.openpgp.org --recv-keys 108F52B48DB57BB0CC439B2997B01419BD92F80A # Ruy Adorno
gpg --keyserver hkps://keys.openpgp.org --recv-keys A363A499291CBBC940DD62E41F10027AF002F8B0 # Ulises Gascón
```
See [Verifying binaries](#verifying-binaries) for how to use these keys to
verify a downloaded file.
<details>
<summary>Other keys used to sign some previous releases</summary>
* **Chris Dickinson** <<christopher.s.dickinson@gmail.com>>
`9554F04D7259F04124DE6B476D5A82AC7E37093B`
* **Colin Ihrig** <<cjihrig@gmail.com>>
`94AE36675C464D64BAFA68DD7434390BDBE9B9C5`
* **Danielle Adams** <<adamzdanielle@gmail.com>>
`1C050899334244A8AF75E53792EF661D867B9DFA`
* **Evan Lucas** <<evanlucas@me.com>>
`B9AE9905FFD7803F25714661B63B535A4C206CA9`
* **Gibson Fahnestock** <<gibfahn@gmail.com>>
`77984A986EBC2AA786BC0F66B01FBB92821C587A`
* **Isaac Z. Schlueter** <<i@izs.me>>
`93C7E9E91B49E432C2F75674B0A78B0A6C481CF6`
* **Italo A. Casas** <<me@italoacasas.com>>
`56730D5401028683275BD23C23EFEFE93C4CFFFE`
* **James M Snell** <<jasnell@keybase.io>>
`71DCFD284A79C3B38668286BC97EC7A07EDE3FC1`
* **Jeremiah Senkpiel** <<fishrock@keybase.io>>
`FD3A5288F042B6850C66B31F09FE44734EB7990E`
* **Juan José Arboleda** <<soyjuanarbol@gmail.com>>
`61FC681DFB92A079F1685E77973F295594EC4689`
* **Julien Gilli** <<jgilli@fastmail.fm>>
`114F43EE0176B71C7BC219DD50A3051F888C628D`
* **Myles Borins** <<myles.borins@gmail.com>>
`C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8`
* **Rod Vagg** <<rod@vagg.org>>
`DD8F2338BAE7501E3DD5AC78C273792F7D83545D`
* **Ruben Bridgewater** <<ruben@bridgewater.de>>
`A48C2BEE680E841632CD4E44F07496B3EB3C1762`
* **Shelley Vohr** <<shelley.vohr@gmail.com>>
`B9E2F5981AA6E0CD28160D9FF13993A75599653C`
* **Timothy J Fontaine** <<tjfontaine@gmail.com>>
`7937DFD2AB06298B2293C3187D33FF9D0246406D`
</details>
### Security release stewards
When possible, the commitment to take slots in the
security release steward rotation is made by companies in order
to ensure individuals who act as security stewards have the
support and recognition from their employer to be able to
prioritize security releases. Security release stewards manage security
releases on a rotation basis as outlined in the
[security release process](./doc/contributing/security-release-process.md).
* [Datadog](https://www.datadoghq.com/)
* [bengl](https://github.com/bengl) -
**Bryan English** <<bryan@bryanenglish.com>> (he/him)
* [NodeSource](https://nodesource.com/)
* [juanarbol](https://github.com/juanarbol) -
**Juan José Arboleda** <<soyjuanarbol@gmail.com>> (he/him)
* [RafaelGSS](https://github.com/RafaelGSS) -
**Rafael Gonzaga** <<rafael.nunu@hotmail.com>> (he/him)
* [Platformatic](https://platformatic.dev/)
* [mcollina](https://github.com/mcollina) -
**Matteo Collina** <<matteo.collina@gmail.com>> (he/him)
* [Red Hat](https://redhat.com) / [IBM](https://ibm.com)
* [joesepi](https://github.com/joesepi) -
**Joe Sepi** <<joesepi@ibm.com>> (he/him)
* [mhdawson](https://github.com/mhdawson) -
**Michael Dawson** <<midawson@redhat.com>> (he/him)
## License
Node.js is available under the
[MIT license](https://opensource.org/licenses/MIT). Node.js also includes
external libraries that are available under a variety of licenses. See
[LICENSE](https://github.com/nodejs/node/blob/HEAD/LICENSE) for the full
license text.
[Code of Conduct]: https://github.com/nodejs/admin/blob/HEAD/CODE_OF_CONDUCT.md
[Contributing to the project]: CONTRIBUTING.md
[Node.js website]: https://nodejs.org/
[OpenJS Foundation]: https://openjsf.org/
[Strategic initiatives]: doc/contributing/strategic-initiatives.md
[Technical values and prioritization]: doc/contributing/technical-values.md
[Working Groups]: https://github.com/nodejs/TSC/blob/HEAD/WORKING_GROUPS.md

View File

Binary file not shown.

View File

@@ -0,0 +1 @@
../lib/node_modules/npm/bin/npm-cli.js

View File

@@ -0,0 +1 @@
../lib/node_modules/npm/bin/npx-cli.js

View File

@@ -0,0 +1,716 @@
{
'variables': {
'configuring_node%': 0,
'asan%': 0,
'ubsan%': 0,
'visibility%': 'hidden', # V8's visibility setting
'target_arch%': 'ia32', # set v8's target architecture
'host_arch%': 'ia32', # set v8's host architecture
'want_separate_host_toolset%': 0, # V8 should not build target and host
'library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds
'component%': 'static_library', # NB. these names match with what V8 expects
'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way
'enable_pgo_generate%': '0',
'enable_pgo_use%': '0',
'python%': 'python',
'node_shared%': 'false',
'force_dynamic_crt%': 0,
'node_use_v8_platform%': 'true',
'node_use_bundled_v8%': 'true',
'node_module_version%': '',
'node_with_ltcg%': '',
'node_shared_openssl%': 'false',
'node_tag%': '',
'uv_library%': 'static_library',
'clang%': 0,
'error_on_warn%': 'false',
'openssl_product': '<(STATIC_LIB_PREFIX)openssl<(STATIC_LIB_SUFFIX)',
'openssl_no_asm%': 0,
# Don't use ICU data file (icudtl.dat) from V8, we use our own.
'icu_use_data_file_flag%': 0,
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.23',
##### V8 defaults for Node.js #####
# Turn on SipHash for hash seed generation, addresses HashWick
'v8_use_siphash': 'true',
# These are more relevant for V8 internal development.
# Refs: https://github.com/nodejs/node/issues/23122
# Refs: https://github.com/nodejs/node/issues/23167
# Enable compiler warnings when using V8_DEPRECATED apis from V8 code.
'v8_deprecation_warnings': 0,
# Enable compiler warnings when using V8_DEPRECATE_SOON apis from V8 code.
'v8_imminent_deprecation_warnings': 0,
# Enable disassembler for `--print-code` v8 options
'v8_enable_disassembler': 1,
# Sets -dOBJECT_PRINT.
'v8_enable_object_print%': 1,
# https://github.com/nodejs/node/pull/22920/files#r222779926
'v8_enable_handle_zapping': 0,
# Disable pointer compression. Can be enabled at build time via configure
# options but default values are required here as this file is also used by
# node-gyp to build addons.
'v8_enable_pointer_compression%': 0,
'v8_enable_31bit_smis_on_64bit_arch%': 0,
# Disable v8 hugepage by default.
'v8_enable_hugepage%': 0,
# This is more of a V8 dev setting
# https://github.com/nodejs/node/pull/22920/files#r222779926
'v8_enable_fast_mksnapshot': 0,
'v8_win64_unwinding_info': 1,
# Variables controlling external defines exposed in public headers.
'v8_enable_conservative_stack_scanning%': 0,
'v8_enable_direct_local%': 0,
'v8_enable_map_packing%': 0,
'v8_enable_pointer_compression_shared_cage%': 0,
'v8_enable_sandbox%': 0,
'v8_enable_v8_checks%': 0,
'v8_enable_zone_compression%': 0,
'v8_use_perfetto': 0,
'tsan%': 0,
##### end V8 defaults #####
'conditions': [
['OS == "win"', {
'os_posix': 0,
'v8_postmortem_support%': 0,
'obj_dir': '<(PRODUCT_DIR)/obj',
'v8_base': '<(PRODUCT_DIR)/lib/libv8_snapshot.a',
}, {
'os_posix': 1,
'v8_postmortem_support%': 1,
}],
['GENERATOR == "ninja"', {
'obj_dir': '<(PRODUCT_DIR)/obj',
'v8_base': '<(PRODUCT_DIR)/obj/tools/v8_gypfiles/libv8_snapshot.a',
}, {
'obj_dir%': '<(PRODUCT_DIR)/obj.target',
'v8_base': '<(PRODUCT_DIR)/obj.target/tools/v8_gypfiles/libv8_snapshot.a',
}],
['OS=="mac"', {
'obj_dir%': '<(PRODUCT_DIR)/obj.target',
'v8_base': '<(PRODUCT_DIR)/libv8_snapshot.a',
}],
# V8 pointer compression only supports 64bit architectures.
['target_arch in "arm ia32 mips mipsel ppc"', {
'v8_enable_pointer_compression': 0,
'v8_enable_31bit_smis_on_64bit_arch': 0,
'v8_enable_sandbox': 0
}],
['target_arch in "ppc64 s390x"', {
'v8_enable_backtrace': 1,
}],
['OS=="linux"', {
'node_section_ordering_info%': ''
}],
['OS == "zos"', {
# use ICU data file on z/OS
'icu_use_data_file_flag%': 1
}]
],
},
'target_defaults': {
'default_configuration': 'Release',
'configurations': {
'Debug': {
'variables': {
'v8_enable_handle_zapping': 1,
'conditions': [
['node_shared != "true"', {
'MSVC_runtimeType': 1, # MultiThreadedDebug (/MTd)
}, {
'MSVC_runtimeType': 3, # MultiThreadedDebugDLL (/MDd)
}],
],
},
'defines': [ 'DEBUG', '_DEBUG' ],
'cflags': [ '-g', '-O0' ],
'conditions': [
['OS in "aix os400"', {
'cflags': [ '-gxcoff' ],
'ldflags': [ '-Wl,-bbigtoc' ],
}],
['OS == "android"', {
'cflags': [ '-fPIC' ],
'ldflags': [ '-fPIC' ]
}],
],
'msvs_settings': {
'VCCLCompilerTool': {
'BasicRuntimeChecks': 3, # /RTC1
'MinimalRebuild': 'false',
'OmitFramePointers': 'false',
'Optimization': 0, # /Od, no optimization
'RuntimeLibrary': '<(MSVC_runtimeType)',
},
'VCLinkerTool': {
'LinkIncremental': 2, # enable incremental linking
},
},
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '0', # stop gyp from defaulting to -Os
},
},
'Release': {
'variables': {
'v8_enable_handle_zapping': 0,
'pgo_generate': ' -fprofile-generate ',
'pgo_use': ' -fprofile-use -fprofile-correction ',
'conditions': [
['node_shared != "true"', {
'MSVC_runtimeType': 0 # MultiThreaded (/MT)
}, {
'MSVC_runtimeType': 2 # MultiThreadedDLL (/MD)
}],
['clang==1', {
'lto': ' -flto ', # Clang
}, {
'lto': ' -flto=4 -fuse-linker-plugin -ffat-lto-objects ', # GCC
}],
],
},
'cflags': [ '-O3' ],
'conditions': [
['enable_lto=="true"', {
'cflags': ['<(lto)'],
'ldflags': ['<(lto)'],
'xcode_settings': {
'LLVM_LTO': 'YES',
},
}],
['OS=="linux"', {
'conditions': [
['node_section_ordering_info!=""', {
'cflags': [
'-fuse-ld=gold',
'-ffunction-sections',
],
'ldflags': [
'-fuse-ld=gold',
'-Wl,--section-ordering-file=<(node_section_ordering_info)',
],
}],
],
}],
['OS=="solaris"', {
# pull in V8's postmortem metadata
'ldflags': [ '-Wl,-z,allextract' ]
}],
['OS=="zos"', {
# increase performance, number from experimentation
'cflags': [ '-qINLINE=::150:100000' ]
}],
['OS!="mac" and OS!="win" and OS!="zos"', {
# -fno-omit-frame-pointer is necessary for the --perf_basic_prof
# flag to work correctly. perf(1) gets confused about JS stack
# frames otherwise, even with --call-graph dwarf.
'cflags': [ '-fno-omit-frame-pointer' ],
}],
['OS=="linux"', {
'conditions': [
['enable_pgo_generate=="true"', {
'cflags': ['<(pgo_generate)'],
'ldflags': ['<(pgo_generate)'],
},],
['enable_pgo_use=="true"', {
'cflags': ['<(pgo_use)'],
'ldflags': ['<(pgo_use)'],
},],
],
},],
['OS == "android"', {
'cflags': [ '-fPIC', '-I<(android_ndk_path)/sources/android/cpufeatures' ],
'ldflags': [ '-fPIC' ]
}],
],
'msvs_settings': {
'VCCLCompilerTool': {
'conditions': [
['target_arch=="arm64"', {
'FloatingPointModel': 1 # /fp:strict
}]
],
'EnableFunctionLevelLinking': 'true',
'EnableIntrinsicFunctions': 'true',
'FavorSizeOrSpeed': 1, # /Ot, favor speed over size
'InlineFunctionExpansion': 2, # /Ob2, inline anything eligible
'OmitFramePointers': 'true',
'Optimization': 3, # /Ox, full optimization
'RuntimeLibrary': '<(MSVC_runtimeType)',
'RuntimeTypeInfo': 'false',
}
},
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '3', # stop gyp from defaulting to -Os
},
}
},
# Defines these mostly for node-gyp to pickup.
'defines': [
'_GLIBCXX_USE_CXX11_ABI=1',
],
# Forcibly disable -Werror. We support a wide range of compilers, it's
# simply not feasible to squelch all warnings, never mind that the
# libraries in deps/ are not under our control.
'conditions': [
[ 'error_on_warn=="false"', {
'cflags!': ['-Werror'],
}, '(_target_name!="<(node_lib_target_name)" or '
'_target_name!="<(node_core_target_name)")', {
'cflags!': ['-Werror'],
}],
],
'msvs_settings': {
'VCCLCompilerTool': {
'AdditionalOptions': [
'/Zc:__cplusplus',
'-std:c++17'
],
'BufferSecurityCheck': 'true',
'DebugInformationFormat': 1, # /Z7 embed info in .obj files
'ExceptionHandling': 0, # /EHsc
'MultiProcessorCompilation': 'true',
'StringPooling': 'true', # pool string literals
'SuppressStartupBanner': 'true',
'WarnAsError': 'false',
'WarningLevel': 3, # /W3
},
'VCLinkerTool': {
'target_conditions': [
['_type=="executable"', {
'SubSystem': 1, # /SUBSYSTEM:CONSOLE
}],
],
'conditions': [
['target_arch=="ia32"', {
'TargetMachine' : 1, # /MACHINE:X86
}],
['target_arch=="x64"', {
'TargetMachine' : 17, # /MACHINE:X64
}],
['target_arch=="arm64"', {
'TargetMachine' : 0, # NotSet. MACHINE:ARM64 is inferred from the input files.
}],
],
'GenerateDebugInformation': 'true',
'SuppressStartupBanner': 'true',
},
},
# Disable warnings:
# - "C4251: class needs to have dll-interface"
# - "C4275: non-DLL-interface used as base for DLL-interface"
# Over 10k of these warnings are generated when compiling node,
# originating from v8.h. Most of them are false positives.
# See also: https://github.com/nodejs/node/pull/15570
# TODO: re-enable when Visual Studio fixes these upstream.
#
# - "C4267: conversion from 'size_t' to 'int'"
# Many any originate from our dependencies, and their sheer number
# drowns out other, more legitimate warnings.
# - "C4244: conversion from 'type1' to 'type2', possible loss of data"
# Ususaly safe. Disable for `dep`, enable for `src`
'msvs_disabled_warnings': [4351, 4355, 4800, 4251, 4275, 4244, 4267],
'msvs_cygwin_shell': 0, # prevent actions from trying to use cygwin
'conditions': [
[ 'configuring_node', {
'msvs_configuration_attributes': {
'OutputDirectory': '<(DEPTH)/out/$(Configuration)/',
'IntermediateDirectory': '$(OutDir)obj/$(ProjectName)/'
},
}],
[ 'target_arch=="x64"', {
'msvs_configuration_platform': 'x64',
}],
[ 'target_arch=="arm64"', {
'msvs_configuration_platform': 'arm64',
}],
['asan == 1 and OS != "mac" and OS != "zos"', {
'cflags+': [
'-fno-omit-frame-pointer',
'-fsanitize=address',
'-fsanitize-address-use-after-scope',
],
'defines': [ 'LEAK_SANITIZER', 'V8_USE_ADDRESS_SANITIZER' ],
'cflags!': [ '-fomit-frame-pointer' ],
'ldflags': [ '-fsanitize=address' ],
}],
['asan == 1 and OS == "mac"', {
'xcode_settings': {
'OTHER_CFLAGS+': [
'-fno-omit-frame-pointer',
'-gline-tables-only',
'-fsanitize=address',
'-DLEAK_SANITIZER'
],
'OTHER_CFLAGS!': [
'-fomit-frame-pointer',
],
},
'target_conditions': [
['_type!="static_library"', {
'xcode_settings': {'OTHER_LDFLAGS': ['-fsanitize=address']},
}],
],
}],
['ubsan == 1 and OS != "mac" and OS != "zos"', {
'cflags+': [
'-fno-omit-frame-pointer',
'-fsanitize=undefined',
],
'defines': [ 'UNDEFINED_SANITIZER'],
'cflags!': [ '-fno-omit-frame-pointer' ],
'ldflags': [ '-fsanitize=undefined' ],
}],
['ubsan == 1 and OS == "mac"', {
'xcode_settings': {
'OTHER_CFLAGS+': [
'-fno-omit-frame-pointer',
'-fsanitize=undefined',
'-DUNDEFINED_SANITIZER'
],
},
'target_conditions': [
['_type!="static_library"', {
'xcode_settings': {'OTHER_LDFLAGS': ['-fsanitize=undefined']},
}],
],
}],
# The defines bellow must include all things from the external_v8_defines
# list in v8/BUILD.gn.
['v8_enable_v8_checks == 1', {
'defines': ['V8_ENABLE_CHECKS'],
}],
['v8_enable_pointer_compression == 1', {
'defines': ['V8_COMPRESS_POINTERS'],
}],
['v8_enable_pointer_compression_shared_cage == 1', {
'defines': ['V8_COMPRESS_POINTERS_IN_SHARED_CAGE'],
}],
['v8_enable_pointer_compression == 1 and v8_enable_pointer_compression_shared_cage != 1', {
'defines': ['V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE'],
}],
['v8_enable_pointer_compression == 1 or v8_enable_31bit_smis_on_64bit_arch == 1', {
'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH'],
}],
['v8_enable_zone_compression == 1', {
'defines': ['V8_COMPRESS_ZONES',],
}],
['v8_enable_sandbox == 1', {
'defines': ['V8_ENABLE_SANDBOX',],
}],
['v8_deprecation_warnings == 1', {
'defines': ['V8_DEPRECATION_WARNINGS',],
}],
['v8_imminent_deprecation_warnings == 1', {
'defines': ['V8_IMMINENT_DEPRECATION_WARNINGS',],
}],
['v8_use_perfetto == 1', {
'defines': ['V8_USE_PERFETTO',],
}],
['v8_enable_map_packing == 1', {
'defines': ['V8_MAP_PACKING',],
}],
['tsan == 1', {
'defines': ['V8_IS_TSAN',],
}],
['v8_enable_conservative_stack_scanning == 1', {
'defines': ['V8_ENABLE_CONSERVATIVE_STACK_SCANNING',],
}],
['v8_enable_direct_local == 1', {
'defines': ['V8_ENABLE_DIRECT_LOCAL',],
}],
['OS == "win"', {
'defines': [
'WIN32',
# we don't really want VC++ warning us about
# how dangerous C functions are...
'_CRT_SECURE_NO_DEPRECATE',
# ... or that C implementations shouldn't use
# POSIX names
'_CRT_NONSTDC_NO_DEPRECATE',
# Make sure the STL doesn't try to use exceptions
'_HAS_EXCEPTIONS=0',
'BUILDING_V8_SHARED=1',
'BUILDING_UV_SHARED=1',
],
}],
[ 'OS in "linux freebsd openbsd solaris aix os400"', {
'cflags': [ '-pthread' ],
'ldflags': [ '-pthread' ],
}],
[ 'OS in "linux freebsd openbsd solaris android aix os400 cloudabi"', {
'cflags': [ '-Wall', '-Wextra', '-Wno-unused-parameter', ],
'cflags_cc': [ '-fno-rtti', '-fno-exceptions', '-std=gnu++17' ],
'defines': [ '__STDC_FORMAT_MACROS' ],
'ldflags': [ '-rdynamic' ],
'target_conditions': [
# The 1990s toolchain on SmartOS can't handle thin archives.
['_type=="static_library" and OS=="solaris"', {
'standalone_static_library': 1,
}],
['OS=="openbsd"', {
'cflags': [ '-I/usr/local/include' ],
'ldflags': [ '-Wl,-z,wxneeded' ],
}],
['_toolset=="host"', {
'conditions': [
[ 'host_arch=="ia32"', {
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
[ 'host_arch=="x64"', {
'cflags': [ '-m64' ],
'ldflags': [ '-m64' ],
}],
[ 'host_arch=="ppc" and OS not in "aix os400"', {
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
[ 'host_arch=="ppc64" and OS not in "aix os400"', {
'cflags': [ '-m64', '-mminimal-toc' ],
'ldflags': [ '-m64' ],
}],
[ 'host_arch=="s390x" and OS=="linux"', {
'cflags': [ '-m64', '-march=z196' ],
'ldflags': [ '-m64', '-march=z196' ],
}],
],
}],
['_toolset=="target"', {
'conditions': [
[ 'target_arch=="ia32"', {
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
[ 'target_arch=="x64"', {
'cflags': [ '-m64' ],
'ldflags': [ '-m64' ],
}],
[ 'target_arch=="ppc" and OS not in "aix os400"', {
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
[ 'target_arch=="ppc64" and OS not in "aix os400"', {
'cflags': [ '-m64', '-mminimal-toc' ],
'ldflags': [ '-m64' ],
}],
[ 'target_arch=="s390x" and OS=="linux"', {
'cflags': [ '-m64', '-march=z196' ],
'ldflags': [ '-m64', '-march=z196' ],
}],
],
}],
],
'conditions': [
[ 'OS=="solaris"', {
'cflags': [ '-pthreads' ],
'ldflags': [ '-pthreads' ],
'cflags!': [ '-pthread' ],
'ldflags!': [ '-pthread' ],
}],
[ 'node_shared=="true"', {
'cflags': [ '-fPIC' ],
}],
],
}],
[ 'OS in "aix os400"', {
'variables': {
# Used to differentiate `AIX` and `OS400`(IBM i).
'aix_variant_name': '<!(uname -s)',
},
'cflags': [ '-maix64', ],
'ldflags!': [ '-rdynamic', ],
'ldflags': [
'-Wl,-bbigtoc',
'-maix64',
],
'conditions': [
[ '"<(aix_variant_name)"=="OS400"', { # a.k.a. `IBM i`
'ldflags': [
'-Wl,-blibpath:/QOpenSys/pkgs/lib:/QOpenSys/usr/lib',
'-Wl,-brtl',
],
}, { # else it's `AIX`
'variables': {
'gcc_major': '<!(<(python) -c "import os; import subprocess; CXX=os.environ.get(\'CXX\', \'g++\'); subprocess.run([CXX, \'-dumpversion\'])")'
},
# Disable the following compiler warning:
#
# warning: visibility attribute not supported in this
# configuration; ignored [-Wattributes]
#
# This is gcc complaining about __attribute((visibility("default"))
# in static library builds. Legitimate but harmless and it drowns
# out more relevant warnings.
'cflags': [ '-Wno-attributes' ],
'ldflags': [
'-Wl,-blibpath:/usr/lib:/lib:/opt/freeware/lib/gcc/powerpc-ibm-aix7.3.0.0/>(gcc_major)/pthread/ppc64:/opt/freeware/lib/gcc/powerpc-ibm-aix7.2.0.0/>(gcc_major)/pthread/ppc64:/opt/freeware/lib/pthread/ppc64',
],
}],
],
}],
['OS=="android"', {
'target_conditions': [
['_toolset=="target"', {
'defines': [ '_GLIBCXX_USE_C99_MATH' ],
'libraries': [ '-llog' ],
}],
['_toolset=="host"', {
'cflags': [ '-pthread' ],
'ldflags': [ '-pthread' ],
}],
],
}],
['OS=="mac"', {
'defines': ['_DARWIN_USE_64_BIT_INODE=1'],
'xcode_settings': {
'ALWAYS_SEARCH_USER_PATHS': 'NO',
'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks
'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic
# (Equivalent to -fPIC)
'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions
'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti
'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings
'PREBINDING': 'NO', # No -Wl,-prebind
'MACOSX_DEPLOYMENT_TARGET': '10.15', # -mmacosx-version-min=10.15
'USE_HEADERMAP': 'NO',
'OTHER_CFLAGS': [
'-fno-strict-aliasing',
],
'WARNING_CFLAGS': [
'-Wall',
'-Wendif-labels',
'-W',
'-Wno-unused-parameter',
],
},
'target_conditions': [
['_type!="static_library"', {
'xcode_settings': {
'OTHER_LDFLAGS': [
'-Wl,-search_paths_first'
],
},
}],
],
'conditions': [
['target_arch=="ia32"', {
'xcode_settings': {'ARCHS': ['i386']},
}],
['target_arch=="x64"', {
'xcode_settings': {'ARCHS': ['x86_64']},
}],
['target_arch=="arm64"', {
'xcode_settings': {
'ARCHS': ['arm64'],
'OTHER_LDFLAGS!': [
'-Wl,-no_pie',
],
},
}],
['clang==1', {
'xcode_settings': {
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++17', # -std=gnu++17
'CLANG_CXX_LIBRARY': 'libc++',
},
}],
],
}],
['OS=="freebsd"', {
'ldflags': [
'-Wl,--export-dynamic',
],
}],
# if node is built as an executable,
# the openssl mechanism for keeping itself "dload"-ed to ensure proper
# atexit cleanup does not apply
['node_shared_openssl!="true" and node_shared!="true"', {
'defines': [
# `OPENSSL_NO_PINSHARED` prevents openssl from dload
# current node executable,
# see https://github.com/nodejs/node/pull/21848
# or https://github.com/nodejs/node/issues/27925
'OPENSSL_NO_PINSHARED'
],
}],
['node_shared_openssl!="true"', {
# `OPENSSL_THREADS` is defined via GYP for openSSL for all architectures.
'defines': [
'OPENSSL_THREADS',
],
}],
['node_shared_openssl!="true" and openssl_no_asm==1', {
'defines': [
'OPENSSL_NO_ASM',
],
}],
['OS == "zos"', {
'defines': [
'_XOPEN_SOURCE_EXTENDED',
'_XOPEN_SOURCE=600',
'_UNIX03_THREADS',
'_UNIX03_WITHDRAWN',
'_UNIX03_SOURCE',
'_OPEN_SYS_SOCK_IPV6',
'_OPEN_SYS_FILE_EXT=1',
'_POSIX_SOURCE',
'_OPEN_SYS',
'_OPEN_SYS_IF_EXT',
'_OPEN_SYS_SOCK_IPV6',
'_OPEN_MSGQ_EXT',
'_LARGE_TIME_API',
'_ALL_SOURCE',
'_AE_BIMODAL=1',
'__IBMCPP_TR1__',
'NODE_PLATFORM="os390"',
'PATH_MAX=1024',
'_ENHANCED_ASCII_EXT=0xFFFFFFFF',
'_Export=extern',
'__static_assert=static_assert',
],
'cflags': [
'-q64',
'-Wc,DLL',
'-Wa,GOFF',
'-qARCH=10',
'-qASCII',
'-qTUNE=12',
'-qENUM=INT',
'-qEXPORTALL',
'-qASM',
],
'cflags_cc': [
'-qxclang=-std=c++14',
],
'ldflags': [
'-q64',
],
# for addons due to v8config.h include of "zos-base.h":
'include_dirs': ['<(zoslib_include_dir)'],
}],
],
}
}

View File

@@ -0,0 +1,411 @@
# Do not edit. Generated by the configure script.
{ 'target_defaults': {'cflags': [], 'default_configuration': 'Release', 'defines': ['NODE_OPENSSL_CONF_NAME=nodejs_conf', 'NODE_OPENSSL_HAS_QUIC', 'ICU_NO_USER_DATA_OVERRIDE'], 'include_dirs': [], 'libraries': []},
'variables': { 'arm_fpu': 'neon',
'asan': 0,
'clang': 1,
'coverage': 'false',
'dcheck_always_on': 0,
'debug_nghttp2': 'false',
'debug_node': 'false',
'enable_lto': 'false',
'enable_pgo_generate': 'false',
'enable_pgo_use': 'false',
'error_on_warn': 'false',
'force_dynamic_crt': 0,
'host_arch': 'arm64',
'icu_data_in': '../../deps/icu-tmp/icudt75l.dat',
'icu_endianness': 'l',
'icu_gyp_path': 'tools/icu/icu-generic.gyp',
'icu_path': 'deps/icu-small',
'icu_small': 'false',
'icu_ver_major': '75',
'is_debug': 0,
'libdir': 'lib',
'llvm_version': '13.0',
'napi_build_version': '9',
'node_builtin_shareable_builtins': ['deps/cjs-module-lexer/lexer.js', 'deps/cjs-module-lexer/dist/lexer.js', 'deps/undici/undici.js'],
'node_byteorder': 'little',
'node_debug_lib': 'false',
'node_enable_d8': 'false',
'node_enable_v8_vtunejit': 'false',
'node_fipsinstall': 'false',
'node_install_corepack': 'true',
'node_install_npm': 'true',
'node_library_files': [ 'lib/_http_agent.js',
'lib/_http_client.js',
'lib/_http_common.js',
'lib/_http_incoming.js',
'lib/_http_outgoing.js',
'lib/_http_server.js',
'lib/_stream_duplex.js',
'lib/_stream_passthrough.js',
'lib/_stream_readable.js',
'lib/_stream_transform.js',
'lib/_stream_wrap.js',
'lib/_stream_writable.js',
'lib/_tls_common.js',
'lib/_tls_wrap.js',
'lib/assert.js',
'lib/assert/strict.js',
'lib/async_hooks.js',
'lib/buffer.js',
'lib/child_process.js',
'lib/cluster.js',
'lib/console.js',
'lib/constants.js',
'lib/crypto.js',
'lib/dgram.js',
'lib/diagnostics_channel.js',
'lib/dns.js',
'lib/dns/promises.js',
'lib/domain.js',
'lib/events.js',
'lib/fs.js',
'lib/fs/promises.js',
'lib/http.js',
'lib/http2.js',
'lib/https.js',
'lib/inspector.js',
'lib/inspector/promises.js',
'lib/internal/abort_controller.js',
'lib/internal/assert.js',
'lib/internal/assert/assertion_error.js',
'lib/internal/assert/calltracker.js',
'lib/internal/assert/utils.js',
'lib/internal/async_hooks.js',
'lib/internal/blob.js',
'lib/internal/blocklist.js',
'lib/internal/bootstrap/node.js',
'lib/internal/bootstrap/realm.js',
'lib/internal/bootstrap/shadow_realm.js',
'lib/internal/bootstrap/switches/does_not_own_process_state.js',
'lib/internal/bootstrap/switches/does_own_process_state.js',
'lib/internal/bootstrap/switches/is_main_thread.js',
'lib/internal/bootstrap/switches/is_not_main_thread.js',
'lib/internal/bootstrap/web/exposed-wildcard.js',
'lib/internal/bootstrap/web/exposed-window-or-worker.js',
'lib/internal/buffer.js',
'lib/internal/child_process.js',
'lib/internal/child_process/serialization.js',
'lib/internal/cli_table.js',
'lib/internal/cluster/child.js',
'lib/internal/cluster/primary.js',
'lib/internal/cluster/round_robin_handle.js',
'lib/internal/cluster/shared_handle.js',
'lib/internal/cluster/utils.js',
'lib/internal/cluster/worker.js',
'lib/internal/console/constructor.js',
'lib/internal/console/global.js',
'lib/internal/constants.js',
'lib/internal/crypto/aes.js',
'lib/internal/crypto/certificate.js',
'lib/internal/crypto/cfrg.js',
'lib/internal/crypto/cipher.js',
'lib/internal/crypto/diffiehellman.js',
'lib/internal/crypto/ec.js',
'lib/internal/crypto/hash.js',
'lib/internal/crypto/hashnames.js',
'lib/internal/crypto/hkdf.js',
'lib/internal/crypto/keygen.js',
'lib/internal/crypto/keys.js',
'lib/internal/crypto/mac.js',
'lib/internal/crypto/pbkdf2.js',
'lib/internal/crypto/random.js',
'lib/internal/crypto/rsa.js',
'lib/internal/crypto/scrypt.js',
'lib/internal/crypto/sig.js',
'lib/internal/crypto/util.js',
'lib/internal/crypto/webcrypto.js',
'lib/internal/crypto/webidl.js',
'lib/internal/crypto/x509.js',
'lib/internal/debugger/inspect.js',
'lib/internal/debugger/inspect_client.js',
'lib/internal/debugger/inspect_repl.js',
'lib/internal/dgram.js',
'lib/internal/dns/callback_resolver.js',
'lib/internal/dns/promises.js',
'lib/internal/dns/utils.js',
'lib/internal/encoding.js',
'lib/internal/error_serdes.js',
'lib/internal/errors.js',
'lib/internal/event_target.js',
'lib/internal/events/abort_listener.js',
'lib/internal/events/symbols.js',
'lib/internal/file.js',
'lib/internal/fixed_queue.js',
'lib/internal/freelist.js',
'lib/internal/freeze_intrinsics.js',
'lib/internal/fs/cp/cp-sync.js',
'lib/internal/fs/cp/cp.js',
'lib/internal/fs/dir.js',
'lib/internal/fs/promises.js',
'lib/internal/fs/read/context.js',
'lib/internal/fs/recursive_watch.js',
'lib/internal/fs/rimraf.js',
'lib/internal/fs/streams.js',
'lib/internal/fs/sync_write_stream.js',
'lib/internal/fs/utils.js',
'lib/internal/fs/watchers.js',
'lib/internal/heap_utils.js',
'lib/internal/histogram.js',
'lib/internal/http.js',
'lib/internal/http2/compat.js',
'lib/internal/http2/core.js',
'lib/internal/http2/util.js',
'lib/internal/idna.js',
'lib/internal/inspector_async_hook.js',
'lib/internal/inspector_network_tracking.js',
'lib/internal/js_stream_socket.js',
'lib/internal/legacy/processbinding.js',
'lib/internal/linkedlist.js',
'lib/internal/main/check_syntax.js',
'lib/internal/main/embedding.js',
'lib/internal/main/eval_stdin.js',
'lib/internal/main/eval_string.js',
'lib/internal/main/inspect.js',
'lib/internal/main/mksnapshot.js',
'lib/internal/main/print_help.js',
'lib/internal/main/prof_process.js',
'lib/internal/main/repl.js',
'lib/internal/main/run_main_module.js',
'lib/internal/main/test_runner.js',
'lib/internal/main/watch_mode.js',
'lib/internal/main/worker_thread.js',
'lib/internal/mime.js',
'lib/internal/modules/cjs/loader.js',
'lib/internal/modules/esm/assert.js',
'lib/internal/modules/esm/create_dynamic_module.js',
'lib/internal/modules/esm/fetch_module.js',
'lib/internal/modules/esm/formats.js',
'lib/internal/modules/esm/get_format.js',
'lib/internal/modules/esm/hooks.js',
'lib/internal/modules/esm/initialize_import_meta.js',
'lib/internal/modules/esm/load.js',
'lib/internal/modules/esm/loader.js',
'lib/internal/modules/esm/module_job.js',
'lib/internal/modules/esm/module_map.js',
'lib/internal/modules/esm/package_config.js',
'lib/internal/modules/esm/resolve.js',
'lib/internal/modules/esm/shared_constants.js',
'lib/internal/modules/esm/translators.js',
'lib/internal/modules/esm/utils.js',
'lib/internal/modules/esm/worker.js',
'lib/internal/modules/helpers.js',
'lib/internal/modules/package_json_reader.js',
'lib/internal/modules/run_main.js',
'lib/internal/navigator.js',
'lib/internal/net.js',
'lib/internal/options.js',
'lib/internal/per_context/domexception.js',
'lib/internal/per_context/messageport.js',
'lib/internal/per_context/primordials.js',
'lib/internal/perf/event_loop_delay.js',
'lib/internal/perf/event_loop_utilization.js',
'lib/internal/perf/nodetiming.js',
'lib/internal/perf/observe.js',
'lib/internal/perf/performance.js',
'lib/internal/perf/performance_entry.js',
'lib/internal/perf/resource_timing.js',
'lib/internal/perf/timerify.js',
'lib/internal/perf/usertiming.js',
'lib/internal/perf/utils.js',
'lib/internal/policy/manifest.js',
'lib/internal/policy/sri.js',
'lib/internal/priority_queue.js',
'lib/internal/process/execution.js',
'lib/internal/process/per_thread.js',
'lib/internal/process/permission.js',
'lib/internal/process/policy.js',
'lib/internal/process/pre_execution.js',
'lib/internal/process/promises.js',
'lib/internal/process/report.js',
'lib/internal/process/signal.js',
'lib/internal/process/task_queues.js',
'lib/internal/process/warning.js',
'lib/internal/process/worker_thread_only.js',
'lib/internal/promise_hooks.js',
'lib/internal/querystring.js',
'lib/internal/readline/callbacks.js',
'lib/internal/readline/emitKeypressEvents.js',
'lib/internal/readline/interface.js',
'lib/internal/readline/promises.js',
'lib/internal/readline/utils.js',
'lib/internal/repl.js',
'lib/internal/repl/await.js',
'lib/internal/repl/history.js',
'lib/internal/repl/utils.js',
'lib/internal/socket_list.js',
'lib/internal/socketaddress.js',
'lib/internal/source_map/prepare_stack_trace.js',
'lib/internal/source_map/source_map.js',
'lib/internal/source_map/source_map_cache.js',
'lib/internal/stream_base_commons.js',
'lib/internal/streams/add-abort-signal.js',
'lib/internal/streams/compose.js',
'lib/internal/streams/destroy.js',
'lib/internal/streams/duplex.js',
'lib/internal/streams/duplexify.js',
'lib/internal/streams/duplexpair.js',
'lib/internal/streams/end-of-stream.js',
'lib/internal/streams/from.js',
'lib/internal/streams/lazy_transform.js',
'lib/internal/streams/legacy.js',
'lib/internal/streams/operators.js',
'lib/internal/streams/passthrough.js',
'lib/internal/streams/pipeline.js',
'lib/internal/streams/readable.js',
'lib/internal/streams/state.js',
'lib/internal/streams/transform.js',
'lib/internal/streams/utils.js',
'lib/internal/streams/writable.js',
'lib/internal/test/binding.js',
'lib/internal/test/transfer.js',
'lib/internal/test_runner/coverage.js',
'lib/internal/test_runner/harness.js',
'lib/internal/test_runner/mock/loader.js',
'lib/internal/test_runner/mock/mock.js',
'lib/internal/test_runner/mock/mock_timers.js',
'lib/internal/test_runner/reporter/dot.js',
'lib/internal/test_runner/reporter/junit.js',
'lib/internal/test_runner/reporter/lcov.js',
'lib/internal/test_runner/reporter/spec.js',
'lib/internal/test_runner/reporter/tap.js',
'lib/internal/test_runner/reporter/utils.js',
'lib/internal/test_runner/reporter/v8-serializer.js',
'lib/internal/test_runner/runner.js',
'lib/internal/test_runner/test.js',
'lib/internal/test_runner/tests_stream.js',
'lib/internal/test_runner/utils.js',
'lib/internal/timers.js',
'lib/internal/tls/secure-context.js',
'lib/internal/tls/secure-pair.js',
'lib/internal/trace_events_async_hooks.js',
'lib/internal/tty.js',
'lib/internal/url.js',
'lib/internal/util.js',
'lib/internal/util/colors.js',
'lib/internal/util/comparisons.js',
'lib/internal/util/debuglog.js',
'lib/internal/util/embedding.js',
'lib/internal/util/inspect.js',
'lib/internal/util/inspector.js',
'lib/internal/util/iterable_weak_map.js',
'lib/internal/util/parse_args/parse_args.js',
'lib/internal/util/parse_args/utils.js',
'lib/internal/util/types.js',
'lib/internal/v8/startup_snapshot.js',
'lib/internal/v8_prof_polyfill.js',
'lib/internal/v8_prof_processor.js',
'lib/internal/validators.js',
'lib/internal/vm.js',
'lib/internal/vm/module.js',
'lib/internal/wasm_web_api.js',
'lib/internal/watch_mode/files_watcher.js',
'lib/internal/watchdog.js',
'lib/internal/webidl.js',
'lib/internal/webstreams/adapters.js',
'lib/internal/webstreams/compression.js',
'lib/internal/webstreams/encoding.js',
'lib/internal/webstreams/queuingstrategies.js',
'lib/internal/webstreams/readablestream.js',
'lib/internal/webstreams/transfer.js',
'lib/internal/webstreams/transformstream.js',
'lib/internal/webstreams/util.js',
'lib/internal/webstreams/writablestream.js',
'lib/internal/worker.js',
'lib/internal/worker/io.js',
'lib/internal/worker/js_transferable.js',
'lib/module.js',
'lib/net.js',
'lib/os.js',
'lib/path.js',
'lib/path/posix.js',
'lib/path/win32.js',
'lib/perf_hooks.js',
'lib/process.js',
'lib/punycode.js',
'lib/querystring.js',
'lib/readline.js',
'lib/readline/promises.js',
'lib/repl.js',
'lib/sea.js',
'lib/stream.js',
'lib/stream/consumers.js',
'lib/stream/promises.js',
'lib/stream/web.js',
'lib/string_decoder.js',
'lib/sys.js',
'lib/test.js',
'lib/test/reporters.js',
'lib/timers.js',
'lib/timers/promises.js',
'lib/tls.js',
'lib/trace_events.js',
'lib/tty.js',
'lib/url.js',
'lib/util.js',
'lib/util/types.js',
'lib/v8.js',
'lib/vm.js',
'lib/wasi.js',
'lib/worker_threads.js',
'lib/zlib.js'],
'node_module_version': 115,
'node_no_browser_globals': 'false',
'node_prefix': '/',
'node_release_urlbase': 'https://nodejs.org/download/release/',
'node_shared': 'false',
'node_shared_ada': 'false',
'node_shared_brotli': 'false',
'node_shared_cares': 'false',
'node_shared_http_parser': 'false',
'node_shared_libuv': 'false',
'node_shared_nghttp2': 'false',
'node_shared_nghttp3': 'false',
'node_shared_ngtcp2': 'false',
'node_shared_openssl': 'false',
'node_shared_simdjson': 'false',
'node_shared_simdutf': 'false',
'node_shared_uvwasi': 'false',
'node_shared_zlib': 'false',
'node_tag': '',
'node_target_type': 'executable',
'node_use_bundled_v8': 'true',
'node_use_node_code_cache': 'true',
'node_use_node_snapshot': 'true',
'node_use_openssl': 'true',
'node_use_v8_platform': 'true',
'node_with_ltcg': 'false',
'node_without_node_options': 'false',
'node_write_snapshot_as_array_literals': 'false',
'openssl_is_fips': 'false',
'openssl_quic': 'true',
'ossfuzz': 'false',
'shlib_suffix': '115.dylib',
'single_executable_application': 'true',
'target_arch': 'arm64',
'ubsan': 0,
'use_prefix_to_find_headers': 'false',
'v8_enable_31bit_smis_on_64bit_arch': 0,
'v8_enable_extensible_ro_snapshot': 0,
'v8_enable_gdbjit': 0,
'v8_enable_hugepage': 0,
'v8_enable_i18n_support': 1,
'v8_enable_inspector': 1,
'v8_enable_javascript_promise_hooks': 1,
'v8_enable_lite_mode': 0,
'v8_enable_maglev': 0,
'v8_enable_object_print': 1,
'v8_enable_pointer_compression': 0,
'v8_enable_sandbox': 0,
'v8_enable_shared_ro_heap': 1,
'v8_enable_v8_checks': 0,
'v8_enable_webassembly': 1,
'v8_no_strict_aliasing': 1,
'v8_optimized_debug': 1,
'v8_promise_internal_field_count': 1,
'v8_random_seed': 0,
'v8_trace_maps': 0,
'v8_use_siphash': 1,
'want_separate_host_toolset': 0,
'xcode_version': '13.0'}}

View File

@@ -0,0 +1,310 @@
// Copyright 2020 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 INCLUDE_CPPGC_ALLOCATION_H_
#define INCLUDE_CPPGC_ALLOCATION_H_
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <new>
#include <type_traits>
#include <utility>
#include "cppgc/custom-space.h"
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/gc-info.h"
#include "cppgc/type-traits.h"
#include "v8config.h" // NOLINT(build/include_directory)
#if defined(__has_attribute)
#if __has_attribute(assume_aligned)
#define CPPGC_DEFAULT_ALIGNED \
__attribute__((assume_aligned(api_constants::kDefaultAlignment)))
#define CPPGC_DOUBLE_WORD_ALIGNED \
__attribute__((assume_aligned(2 * api_constants::kDefaultAlignment)))
#endif // __has_attribute(assume_aligned)
#endif // defined(__has_attribute)
#if !defined(CPPGC_DEFAULT_ALIGNED)
#define CPPGC_DEFAULT_ALIGNED
#endif
#if !defined(CPPGC_DOUBLE_WORD_ALIGNED)
#define CPPGC_DOUBLE_WORD_ALIGNED
#endif
namespace cppgc {
/**
* AllocationHandle is used to allocate garbage-collected objects.
*/
class AllocationHandle;
namespace internal {
// Similar to C++17 std::align_val_t;
enum class AlignVal : size_t {};
class V8_EXPORT MakeGarbageCollectedTraitInternal {
protected:
static inline void MarkObjectAsFullyConstructed(const void* payload) {
// See api_constants for an explanation of the constants.
std::atomic<uint16_t>* atomic_mutable_bitfield =
reinterpret_cast<std::atomic<uint16_t>*>(
const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
reinterpret_cast<const uint8_t*>(payload) -
api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
// It's safe to split use load+store here (instead of a read-modify-write
// operation), since it's guaranteed that this 16-bit bitfield is only
// modified by a single thread. This is cheaper in terms of code bloat (on
// ARM) and performance.
uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed);
value |= api_constants::kFullyConstructedBitMask;
atomic_mutable_bitfield->store(value, std::memory_order_release);
}
// Dispatch based on compile-time information.
//
// Default implementation is for a custom space with >`kDefaultAlignment` byte
// alignment.
template <typename GCInfoType, typename CustomSpace, size_t alignment>
struct AllocationDispatcher final {
static void* Invoke(AllocationHandle& handle, size_t size) {
static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
"Custom space must inherit from CustomSpaceBase.");
static_assert(
!CustomSpace::kSupportsCompaction,
"Custom spaces that support compaction do not support allocating "
"objects with non-default (i.e. word-sized) alignment.");
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, static_cast<AlignVal>(alignment),
internal::GCInfoTrait<GCInfoType>::Index(), CustomSpace::kSpaceIndex);
}
};
// Fast path for regular allocations for the default space with
// `kDefaultAlignment` byte alignment.
template <typename GCInfoType>
struct AllocationDispatcher<GCInfoType, void,
api_constants::kDefaultAlignment>
final {
static void* Invoke(AllocationHandle& handle, size_t size) {
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, internal::GCInfoTrait<GCInfoType>::Index());
}
};
// Default space with >`kDefaultAlignment` byte alignment.
template <typename GCInfoType, size_t alignment>
struct AllocationDispatcher<GCInfoType, void, alignment> final {
static void* Invoke(AllocationHandle& handle, size_t size) {
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, static_cast<AlignVal>(alignment),
internal::GCInfoTrait<GCInfoType>::Index());
}
};
// Custom space with `kDefaultAlignment` byte alignment.
template <typename GCInfoType, typename CustomSpace>
struct AllocationDispatcher<GCInfoType, CustomSpace,
api_constants::kDefaultAlignment>
final {
static void* Invoke(AllocationHandle& handle, size_t size) {
static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
"Custom space must inherit from CustomSpaceBase.");
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, internal::GCInfoTrait<GCInfoType>::Index(),
CustomSpace::kSpaceIndex);
}
};
private:
static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t,
GCInfoIndex);
static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&,
size_t, AlignVal,
GCInfoIndex);
static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t,
GCInfoIndex, CustomSpaceIndex);
static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&,
size_t, AlignVal, GCInfoIndex,
CustomSpaceIndex);
friend class HeapObjectHeader;
};
} // namespace internal
/**
* Base trait that provides utilities for advancers users that have custom
* allocation needs (e.g., overriding size). It's expected that users override
* MakeGarbageCollectedTrait (see below) and inherit from
* MakeGarbageCollectedTraitBase and make use of the low-level primitives
* offered to allocate and construct an object.
*/
template <typename T>
class MakeGarbageCollectedTraitBase
: private internal::MakeGarbageCollectedTraitInternal {
private:
static_assert(internal::IsGarbageCollectedType<T>::value,
"T needs to be a garbage collected object");
static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
sizeof(T) <=
internal::api_constants::kLargeObjectSizeThreshold,
"GarbageCollectedMixin may not be a large object");
protected:
/**
* Allocates memory for an object of type T.
*
* \param handle AllocationHandle identifying the heap to allocate the object
* on.
* \param size The size that should be reserved for the object.
* \returns the memory to construct an object of type T on.
*/
V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
static_assert(
std::is_base_of<typename T::ParentMostGarbageCollectedType, T>::value,
"U of GarbageCollected<U> must be a base of T. Check "
"GarbageCollected<T> base class inheritance.");
static constexpr size_t kWantedAlignment =
alignof(T) < internal::api_constants::kDefaultAlignment
? internal::api_constants::kDefaultAlignment
: alignof(T);
static_assert(
kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
"Requested alignment larger than alignof(std::max_align_t) bytes. "
"Please file a bug to possibly get this restriction lifted.");
return AllocationDispatcher<
typename internal::GCInfoFolding<
T, typename T::ParentMostGarbageCollectedType>::ResultType,
typename SpaceTrait<T>::Space, kWantedAlignment>::Invoke(handle, size);
}
/**
* Marks an object as fully constructed, resulting in precise handling by the
* garbage collector.
*
* \param payload The base pointer the object is allocated at.
*/
V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
payload);
}
};
/**
* Passed to MakeGarbageCollected to specify how many bytes should be appended
* to the allocated object.
*
* Example:
* \code
* class InlinedArray final : public GarbageCollected<InlinedArray> {
* public:
* explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
* void Trace(Visitor*) const {}
* size_t size;
* char* byte_array;
* };
*
* auto* inlined_array = MakeGarbageCollected<InlinedArray(
* GetAllocationHandle(), AdditionalBytes(4), 4);
* for (size_t i = 0; i < 4; i++) {
* Process(inlined_array->byte_array[i]);
* }
* \endcode
*/
struct AdditionalBytes {
constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
const size_t value;
};
/**
* Default trait class that specifies how to construct an object of type T.
* Advanced users may override how an object is constructed using the utilities
* that are provided through MakeGarbageCollectedTraitBase.
*
* Any trait overriding construction must
* - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
* - mark the object as fully constructed using
* `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
*/
template <typename T>
class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> {
public:
template <typename... Args>
static T* Call(AllocationHandle& handle, Args&&... args) {
void* memory =
MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
T* object = ::new (memory) T(std::forward<Args>(args)...);
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
return object;
}
template <typename... Args>
static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
Args&&... args) {
void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
handle, sizeof(T) + additional_bytes.value);
T* object = ::new (memory) T(std::forward<Args>(args)...);
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
return object;
}
};
/**
* Allows users to specify a post-construction callback for specific types. The
* callback is invoked on the instance of type T right after it has been
* constructed. This can be useful when the callback requires a
* fully-constructed object to be able to dispatch to virtual methods.
*/
template <typename T, typename = void>
struct PostConstructionCallbackTrait {
static void Call(T*) {}
};
/**
* Constructs a managed object of type T where T transitively inherits from
* GarbageCollected.
*
* \param args List of arguments with which an instance of T will be
* constructed.
* \returns an instance of type T.
*/
template <typename T, typename... Args>
V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
T* object =
MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
PostConstructionCallbackTrait<T>::Call(object);
return object;
}
/**
* Constructs a managed object of type T where T transitively inherits from
* GarbageCollected. Created objects will have additional bytes appended to
* it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
*
* \param additional_bytes Denotes how many bytes to append to T.
* \param args List of arguments with which an instance of T will be
* constructed.
* \returns an instance of type T.
*/
template <typename T, typename... Args>
V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
AdditionalBytes additional_bytes,
Args&&... args) {
T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
std::forward<Args>(args)...);
PostConstructionCallbackTrait<T>::Call(object);
return object;
}
} // namespace cppgc
#undef CPPGC_DEFAULT_ALIGNED
#undef CPPGC_DOUBLE_WORD_ALIGNED
#endif // INCLUDE_CPPGC_ALLOCATION_H_

View File

@@ -0,0 +1,28 @@
// Copyright 2020 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 INCLUDE_CPPGC_COMMON_H_
#define INCLUDE_CPPGC_COMMON_H_
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* Indicator for the stack state of the embedder.
*/
enum class EmbedderStackState {
/**
* Stack may contain interesting heap pointers.
*/
kMayContainHeapPointers,
/**
* Stack does not contain any interesting heap pointers.
*/
kNoHeapPointers,
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_COMMON_H_

View File

@@ -0,0 +1,466 @@
// Copyright 2020 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 INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
#include <atomic>
#include "cppgc/internal/persistent-node.h"
#include "cppgc/internal/pointer-policies.h"
#include "cppgc/persistent.h"
#include "cppgc/visitor.h"
namespace cppgc {
namespace internal {
// Wrapper around PersistentBase that allows accessing poisoned memory when
// using ASAN. This is needed as the GC of the heap that owns the value
// of a CTP, may clear it (heap termination, weakness) while the object
// holding the CTP may be poisoned as itself may be deemed dead.
class CrossThreadPersistentBase : public PersistentBase {
public:
CrossThreadPersistentBase() = default;
explicit CrossThreadPersistentBase(const void* raw) : PersistentBase(raw) {}
V8_CLANG_NO_SANITIZE("address") const void* GetValueFromGC() const {
return raw_;
}
V8_CLANG_NO_SANITIZE("address")
PersistentNode* GetNodeFromGC() const { return node_; }
V8_CLANG_NO_SANITIZE("address")
void ClearFromGC() const {
raw_ = nullptr;
SetNodeSafe(nullptr);
}
// GetNodeSafe() can be used for a thread-safe IsValid() check in a
// double-checked locking pattern. See ~BasicCrossThreadPersistent.
PersistentNode* GetNodeSafe() const {
return reinterpret_cast<std::atomic<PersistentNode*>*>(&node_)->load(
std::memory_order_acquire);
}
// The GC writes using SetNodeSafe() while holding the lock.
V8_CLANG_NO_SANITIZE("address")
void SetNodeSafe(PersistentNode* value) const {
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define V8_IS_ASAN 1
#endif
#endif
#ifdef V8_IS_ASAN
__atomic_store(&node_, &value, __ATOMIC_RELEASE);
#else // !V8_IS_ASAN
// Non-ASAN builds can use atomics. This also covers MSVC which does not
// have the __atomic_store intrinsic.
reinterpret_cast<std::atomic<PersistentNode*>*>(&node_)->store(
value, std::memory_order_release);
#endif // !V8_IS_ASAN
#undef V8_IS_ASAN
}
};
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
class BasicCrossThreadPersistent final : public CrossThreadPersistentBase,
public LocationPolicy,
private WeaknessPolicy,
private CheckingPolicy {
public:
using typename WeaknessPolicy::IsStrongPersistent;
using PointeeType = T;
~BasicCrossThreadPersistent() {
// This implements fast path for destroying empty/sentinel.
//
// Simplified version of `AssignUnsafe()` to allow calling without a
// complete type `T`. Uses double-checked locking with a simple thread-safe
// check for a valid handle based on a node.
if (GetNodeSafe()) {
PersistentRegionLock guard;
const void* old_value = GetValue();
// The fast path check (GetNodeSafe()) does not acquire the lock. Recheck
// validity while holding the lock to ensure the reference has not been
// cleared.
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
region.FreeNode(GetNode());
SetNode(nullptr);
} else {
CPPGC_DCHECK(!GetNode());
}
}
// No need to call SetValue() as the handle is not used anymore. This can
// leave behind stale sentinel values but will always destroy the underlying
// node.
}
BasicCrossThreadPersistent(
const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicCrossThreadPersistent(
std::nullptr_t, const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicCrossThreadPersistent(
SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
: CrossThreadPersistentBase(s), LocationPolicy(loc) {}
BasicCrossThreadPersistent(
T* raw, const SourceLocation& loc = SourceLocation::Current())
: CrossThreadPersistentBase(raw), LocationPolicy(loc) {
if (!IsValid(raw)) return;
PersistentRegionLock guard;
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
SetNode(region.AllocateNode(this, &TraceAsRoot));
this->CheckPointer(raw);
}
class UnsafeCtorTag {
private:
UnsafeCtorTag() = default;
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy>
friend class BasicCrossThreadPersistent;
};
BasicCrossThreadPersistent(
UnsafeCtorTag, T* raw,
const SourceLocation& loc = SourceLocation::Current())
: CrossThreadPersistentBase(raw), LocationPolicy(loc) {
if (!IsValid(raw)) return;
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
SetNode(region.AllocateNode(this, &TraceAsRoot));
this->CheckPointer(raw);
}
BasicCrossThreadPersistent(
T& raw, const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(&raw, loc) {}
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename MemberStorageType,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent(
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
MemberCheckingPolicy, MemberStorageType>
member,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(member.Get(), loc) {}
BasicCrossThreadPersistent(
const BasicCrossThreadPersistent& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(loc) {
// Invoke operator=.
*this = other;
}
// Heterogeneous ctor.
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent(
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
OtherLocationPolicy,
OtherCheckingPolicy>& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(loc) {
*this = other;
}
BasicCrossThreadPersistent(
BasicCrossThreadPersistent&& other,
const SourceLocation& loc = SourceLocation::Current()) noexcept {
// Invoke operator=.
*this = std::move(other);
}
BasicCrossThreadPersistent& operator=(
const BasicCrossThreadPersistent& other) {
PersistentRegionLock guard;
AssignSafe(guard, other.Get());
return *this;
}
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent& operator=(
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
OtherLocationPolicy,
OtherCheckingPolicy>& other) {
PersistentRegionLock guard;
AssignSafe(guard, other.Get());
return *this;
}
BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) {
if (this == &other) return *this;
Clear();
PersistentRegionLock guard;
PersistentBase::operator=(std::move(other));
LocationPolicy::operator=(std::move(other));
if (!IsValid(GetValue())) return *this;
GetNode()->UpdateOwner(this);
other.SetValue(nullptr);
other.SetNode(nullptr);
this->CheckPointer(Get());
return *this;
}
/**
* Assigns a raw pointer.
*
* Note: **Not thread-safe.**
*/
BasicCrossThreadPersistent& operator=(T* other) {
AssignUnsafe(other);
return *this;
}
// Assignment from member.
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename MemberStorageType,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent& operator=(
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
MemberCheckingPolicy, MemberStorageType>
member) {
return operator=(member.Get());
}
/**
* Assigns a nullptr.
*
* \returns the handle.
*/
BasicCrossThreadPersistent& operator=(std::nullptr_t) {
Clear();
return *this;
}
/**
* Assigns the sentinel pointer.
*
* \returns the handle.
*/
BasicCrossThreadPersistent& operator=(SentinelPointer s) {
PersistentRegionLock guard;
AssignSafe(guard, s);
return *this;
}
/**
* Returns a pointer to the stored object.
*
* Note: **Not thread-safe.**
*
* \returns a pointer to the stored object.
*/
// CFI cast exemption to allow passing SentinelPointer through T* and support
// heterogeneous assignments between different Member and Persistent handles
// based on their actual types.
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
return static_cast<T*>(const_cast<void*>(GetValue()));
}
/**
* Clears the stored object.
*/
void Clear() {
PersistentRegionLock guard;
AssignSafe(guard, nullptr);
}
/**
* Returns a pointer to the stored object and releases it.
*
* Note: **Not thread-safe.**
*
* \returns a pointer to the stored object.
*/
T* Release() {
T* result = Get();
Clear();
return result;
}
/**
* Conversio to boolean.
*
* Note: **Not thread-safe.**
*
* \returns true if an actual object has been stored and false otherwise.
*/
explicit operator bool() const { return Get(); }
/**
* Conversion to object of type T.
*
* Note: **Not thread-safe.**
*
* \returns the object.
*/
operator T*() const { return Get(); }
/**
* Dereferences the stored object.
*
* Note: **Not thread-safe.**
*/
T* operator->() const { return Get(); }
T& operator*() const { return *Get(); }
template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
typename OtherLocationPolicy = LocationPolicy,
typename OtherCheckingPolicy = CheckingPolicy>
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>
To() const {
using OtherBasicCrossThreadPersistent =
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>;
PersistentRegionLock guard;
return OtherBasicCrossThreadPersistent(
typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(),
static_cast<U*>(Get()));
}
template <typename U = T,
typename = typename std::enable_if<!BasicCrossThreadPersistent<
U, WeaknessPolicy>::IsStrongPersistent::value>::type>
BasicCrossThreadPersistent<U, internal::StrongCrossThreadPersistentPolicy>
Lock() const {
return BasicCrossThreadPersistent<
U, internal::StrongCrossThreadPersistentPolicy>(*this);
}
private:
static bool IsValid(const void* ptr) {
return ptr && ptr != kSentinelPointer;
}
static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
root_visitor.Trace(*static_cast<const BasicCrossThreadPersistent*>(ptr));
}
void AssignUnsafe(T* ptr) {
const void* old_value = GetValue();
if (IsValid(old_value)) {
PersistentRegionLock guard;
old_value = GetValue();
// The fast path check (IsValid()) does not acquire the lock. Reload
// the value to ensure the reference has not been cleared.
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
if (IsValid(ptr) && (&region == &this->GetPersistentRegion(ptr))) {
SetValue(ptr);
this->CheckPointer(ptr);
return;
}
region.FreeNode(GetNode());
SetNode(nullptr);
} else {
CPPGC_DCHECK(!GetNode());
}
}
SetValue(ptr);
if (!IsValid(ptr)) return;
PersistentRegionLock guard;
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
this->CheckPointer(ptr);
}
void AssignSafe(PersistentRegionLock&, T* ptr) {
PersistentRegionLock::AssertLocked();
const void* old_value = GetValue();
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
if (IsValid(ptr) && (&region == &this->GetPersistentRegion(ptr))) {
SetValue(ptr);
this->CheckPointer(ptr);
return;
}
region.FreeNode(GetNode());
SetNode(nullptr);
}
SetValue(ptr);
if (!IsValid(ptr)) return;
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
this->CheckPointer(ptr);
}
void ClearFromGC() const {
if (IsValid(GetValueFromGC())) {
WeaknessPolicy::GetPersistentRegion(GetValueFromGC())
.FreeNode(GetNodeFromGC());
CrossThreadPersistentBase::ClearFromGC();
}
}
// See Get() for details.
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
T* GetFromGC() const {
return static_cast<T*>(const_cast<void*>(GetValueFromGC()));
}
friend class internal::RootVisitor;
};
template <typename T, typename LocationPolicy, typename CheckingPolicy>
struct IsWeak<
BasicCrossThreadPersistent<T, internal::WeakCrossThreadPersistentPolicy,
LocationPolicy, CheckingPolicy>>
: std::true_type {};
} // namespace internal
namespace subtle {
/**
* **DO NOT USE: Has known caveats, see below.**
*
* CrossThreadPersistent allows retaining objects from threads other than the
* thread the owning heap is operating on.
*
* Known caveats:
* - Does not protect the heap owning an object from terminating.
* - Reaching transitively through the graph is unsupported as objects may be
* moved concurrently on the thread owning the object.
*/
template <typename T>
using CrossThreadPersistent = internal::BasicCrossThreadPersistent<
T, internal::StrongCrossThreadPersistentPolicy>;
/**
* **DO NOT USE: Has known caveats, see below.**
*
* CrossThreadPersistent allows weakly retaining objects from threads other than
* the thread the owning heap is operating on.
*
* Known caveats:
* - Does not protect the heap owning an object from terminating.
* - Reaching transitively through the graph is unsupported as objects may be
* moved concurrently on the thread owning the object.
*/
template <typename T>
using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent<
T, internal::WeakCrossThreadPersistentPolicy>;
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_

View File

@@ -0,0 +1,97 @@
// Copyright 2020 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 INCLUDE_CPPGC_CUSTOM_SPACE_H_
#define INCLUDE_CPPGC_CUSTOM_SPACE_H_
#include <stddef.h>
namespace cppgc {
/**
* Index identifying a custom space.
*/
struct CustomSpaceIndex {
constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT
size_t value;
};
/**
* Top-level base class for custom spaces. Users must inherit from CustomSpace
* below.
*/
class CustomSpaceBase {
public:
virtual ~CustomSpaceBase() = default;
virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0;
virtual bool IsCompactable() const = 0;
};
/**
* Base class custom spaces should directly inherit from. The class inheriting
* from `CustomSpace` must define `kSpaceIndex` as unique space index. These
* indices need for form a sequence starting at 0.
*
* Example:
* \code
* class CustomSpace1 : public CustomSpace<CustomSpace1> {
* public:
* static constexpr CustomSpaceIndex kSpaceIndex = 0;
* };
* class CustomSpace2 : public CustomSpace<CustomSpace2> {
* public:
* static constexpr CustomSpaceIndex kSpaceIndex = 1;
* };
* \endcode
*/
template <typename ConcreteCustomSpace>
class CustomSpace : public CustomSpaceBase {
public:
/**
* Compaction is only supported on spaces that manually manage slots
* recording.
*/
static constexpr bool kSupportsCompaction = false;
CustomSpaceIndex GetCustomSpaceIndex() const final {
return ConcreteCustomSpace::kSpaceIndex;
}
bool IsCompactable() const final {
return ConcreteCustomSpace::kSupportsCompaction;
}
};
/**
* User-overridable trait that allows pinning types to custom spaces.
*/
template <typename T, typename = void>
struct SpaceTrait {
using Space = void;
};
namespace internal {
template <typename CustomSpace>
struct IsAllocatedOnCompactableSpaceImpl {
static constexpr bool value = CustomSpace::kSupportsCompaction;
};
template <>
struct IsAllocatedOnCompactableSpaceImpl<void> {
// Non-custom spaces are by default not compactable.
static constexpr bool value = false;
};
template <typename T>
struct IsAllocatedOnCompactableSpace {
public:
static constexpr bool value =
IsAllocatedOnCompactableSpaceImpl<typename SpaceTrait<T>::Space>::value;
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_

View File

@@ -0,0 +1,67 @@
// Copyright 2020 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 INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
#include <memory>
#include "cppgc/platform.h"
#include "libplatform/libplatform.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* Platform provided by cppgc. Uses V8's DefaultPlatform provided by
* libplatform internally. Exception: `GetForegroundTaskRunner()`, see below.
*/
class V8_EXPORT DefaultPlatform : public Platform {
public:
using IdleTaskSupport = v8::platform::IdleTaskSupport;
explicit DefaultPlatform(
int thread_pool_size = 0,
IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
std::unique_ptr<TracingController> tracing_controller = {})
: v8_platform_(v8::platform::NewDefaultPlatform(
thread_pool_size, idle_task_support,
v8::platform::InProcessStackDumping::kDisabled,
std::move(tracing_controller))) {}
cppgc::PageAllocator* GetPageAllocator() override {
return v8_platform_->GetPageAllocator();
}
double MonotonicallyIncreasingTime() override {
return v8_platform_->MonotonicallyIncreasingTime();
}
std::shared_ptr<cppgc::TaskRunner> GetForegroundTaskRunner() override {
// V8's default platform creates a new task runner when passed the
// `v8::Isolate` pointer the first time. For non-default platforms this will
// require getting the appropriate task runner.
return v8_platform_->GetForegroundTaskRunner(kNoIsolate);
}
std::unique_ptr<cppgc::JobHandle> PostJob(
cppgc::TaskPriority priority,
std::unique_ptr<cppgc::JobTask> job_task) override {
return v8_platform_->PostJob(priority, std::move(job_task));
}
TracingController* GetTracingController() override {
return v8_platform_->GetTracingController();
}
v8::Platform* GetV8Platform() const { return v8_platform_.get(); }
protected:
static constexpr v8::Isolate* kNoIsolate = nullptr;
std::unique_ptr<v8::Platform> v8_platform_;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_

View File

@@ -0,0 +1,30 @@
// Copyright 2020 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 INCLUDE_CPPGC_EPHEMERON_PAIR_H_
#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_
#include "cppgc/liveness-broker.h"
#include "cppgc/member.h"
namespace cppgc {
/**
* An ephemeron pair is used to conditionally retain an object.
* The `value` will be kept alive only if the `key` is alive.
*/
template <typename K, typename V>
struct EphemeronPair {
EphemeronPair(K* k, V* v) : key(k), value(v) {}
WeakMember<K> key;
Member<V> value;
void ClearValueIfKeyIsDead(const LivenessBroker& broker) {
if (!broker.IsHeapObjectAlive(key)) value = nullptr;
}
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_

View File

@@ -0,0 +1,100 @@
// Copyright 2021 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 INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#include <cstddef>
#include "cppgc/allocation.h"
#include "cppgc/internal/logging.h"
#include "cppgc/type-traits.h"
namespace cppgc {
class HeapHandle;
namespace subtle {
template <typename T>
void FreeUnreferencedObject(HeapHandle& heap_handle, T& object);
template <typename T>
bool Resize(T& object, AdditionalBytes additional_bytes);
} // namespace subtle
namespace internal {
class ExplicitManagementImpl final {
private:
V8_EXPORT static void FreeUnreferencedObject(HeapHandle&, void*);
V8_EXPORT static bool Resize(void*, size_t);
template <typename T>
friend void subtle::FreeUnreferencedObject(HeapHandle&, T&);
template <typename T>
friend bool subtle::Resize(T&, AdditionalBytes);
};
} // namespace internal
namespace subtle {
/**
* Informs the garbage collector that `object` can be immediately reclaimed. The
* destructor may not be invoked immediately but only on next garbage
* collection.
*
* It is up to the embedder to guarantee that no other object holds a reference
* to `object` after calling `FreeUnreferencedObject()`. In case such a
* reference exists, it's use results in a use-after-free.
*
* To aid in using the API, `FreeUnreferencedObject()` may be called from
* destructors on objects that would be reclaimed in the same garbage collection
* cycle.
*
* \param heap_handle The corresponding heap.
* \param object Reference to an object that is of type `GarbageCollected` and
* should be immediately reclaimed.
*/
template <typename T>
void FreeUnreferencedObject(HeapHandle& heap_handle, T& object) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
internal::ExplicitManagementImpl::FreeUnreferencedObject(heap_handle,
&object);
}
/**
* Tries to resize `object` of type `T` with additional bytes on top of
* sizeof(T). Resizing is only useful with trailing inlined storage, see e.g.
* `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`.
*
* `Resize()` performs growing or shrinking as needed and may skip the operation
* for internal reasons, see return value.
*
* It is up to the embedder to guarantee that in case of shrinking a larger
* object down, the reclaimed area is not used anymore. Any subsequent use
* results in a use-after-free.
*
* The `object` must be live when calling `Resize()`.
*
* \param object Reference to an object that is of type `GarbageCollected` and
* should be resized.
* \param additional_bytes Bytes in addition to sizeof(T) that the object should
* provide.
* \returns true when the operation was successful and the result can be relied
* on, and false otherwise.
*/
template <typename T>
bool Resize(T& object, AdditionalBytes additional_bytes) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
return internal::ExplicitManagementImpl::Resize(
&object, sizeof(T) + additional_bytes.value);
}
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_

View File

@@ -0,0 +1,106 @@
// Copyright 2020 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 INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
#include "cppgc/internal/api-constants.h"
#include "cppgc/platform.h"
#include "cppgc/trace-trait.h"
#include "cppgc/type-traits.h"
namespace cppgc {
class Visitor;
/**
* Base class for managed objects. Only descendent types of `GarbageCollected`
* can be constructed using `MakeGarbageCollected()`. Must be inherited from as
* left-most base class.
*
* Types inheriting from GarbageCollected must provide a method of
* signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
* pointers to the visitor and delegates to garbage-collected base classes.
* The method must be virtual if the type is not directly a child of
* GarbageCollected and marked as final.
*
* \code
* // Example using final class.
* class FinalType final : public GarbageCollected<FinalType> {
* public:
* void Trace(cppgc::Visitor* visitor) const {
* // Dispatch using visitor->Trace(...);
* }
* };
*
* // Example using non-final base class.
* class NonFinalBase : public GarbageCollected<NonFinalBase> {
* public:
* virtual void Trace(cppgc::Visitor*) const {}
* };
*
* class FinalChild final : public NonFinalBase {
* public:
* void Trace(cppgc::Visitor* visitor) const final {
* // Dispatch using visitor->Trace(...);
* NonFinalBase::Trace(visitor);
* }
* };
* \endcode
*/
template <typename T>
class GarbageCollected {
public:
using IsGarbageCollectedTypeMarker = void;
using ParentMostGarbageCollectedType = T;
// Must use MakeGarbageCollected.
void* operator new(size_t) = delete;
void* operator new[](size_t) = delete;
// The garbage collector is taking care of reclaiming the object. Also,
// virtual destructor requires an unambiguous, accessible 'operator delete'.
void operator delete(void*) {
#ifdef V8_ENABLE_CHECKS
internal::Fatal(
"Manually deleting a garbage collected object is not allowed");
#endif // V8_ENABLE_CHECKS
}
void operator delete[](void*) = delete;
protected:
GarbageCollected() = default;
};
/**
* Base class for managed mixin objects. Such objects cannot be constructed
* directly but must be mixed into the inheritance hierarchy of a
* GarbageCollected object.
*
* Types inheriting from GarbageCollectedMixin must override a virtual method
* of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
* pointers to the visitor and delegates to base classes.
*
* \code
* class Mixin : public GarbageCollectedMixin {
* public:
* void Trace(cppgc::Visitor* visitor) const override {
* // Dispatch using visitor->Trace(...);
* }
* };
* \endcode
*/
class GarbageCollectedMixin {
public:
using IsGarbageCollectedMixinTypeMarker = void;
/**
* This Trace method must be overriden by objects inheriting from
* GarbageCollectedMixin.
*/
virtual void Trace(cppgc::Visitor*) const {}
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_

View File

@@ -0,0 +1,309 @@
// Copyright 2020 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 INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
#include <cstddef>
#include "cppgc/internal/write-barrier.h"
#include "cppgc/macros.h"
#include "cppgc/member.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class HeapHandle;
namespace subtle {
/**
* **DO NOT USE: Use the appropriate managed types.**
*
* Consistency helpers that aid in maintaining a consistent internal state of
* the garbage collector.
*/
class HeapConsistency final {
public:
using WriteBarrierParams = internal::WriteBarrier::Params;
using WriteBarrierType = internal::WriteBarrier::Type;
/**
* Gets the required write barrier type for a specific write.
*
* \param slot Slot containing the pointer to the object. The slot itself
* must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
* \param value The pointer to the object. May be an interior pointer to an
* interface of the actual object.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
static V8_INLINE WriteBarrierType GetWriteBarrierType(
const void* slot, const void* value, WriteBarrierParams& params) {
return internal::WriteBarrier::GetWriteBarrierType(slot, value, params);
}
/**
* Gets the required write barrier type for a specific write. This override is
* only used for all the BasicMember types.
*
* \param slot Slot containing the pointer to the object. The slot itself
* must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
* \param value The pointer to the object held via `BasicMember`.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
static V8_INLINE WriteBarrierType GetWriteBarrierType(
const internal::BasicMember<T, WeaknessTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>& value,
WriteBarrierParams& params) {
return internal::WriteBarrier::GetWriteBarrierType(
value.GetRawSlot(), value.GetRawStorage(), params);
}
/**
* Gets the required write barrier type for a specific write.
*
* \param slot Slot to some part of an object. The object must not necessarily
have been allocated using `MakeGarbageCollected()` but can also live
off-heap or on stack.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \param callback Callback returning the corresponding heap handle. The
* callback is only invoked if the heap cannot otherwise be figured out. The
* callback must not allocate.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrierType
GetWriteBarrierType(const void* slot, WriteBarrierParams& params,
HeapHandleCallback callback) {
return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback);
}
/**
* Gets the required write barrier type for a specific write.
* This version is meant to be used in conjunction with with a marking write
* barrier barrier which doesn't consider the slot.
*
* \param value The pointer to the object. May be an interior pointer to an
* interface of the actual object.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
static V8_INLINE WriteBarrierType
GetWriteBarrierType(const void* value, WriteBarrierParams& params) {
return internal::WriteBarrier::GetWriteBarrierType(value, params);
}
/**
* Conservative Dijkstra-style write barrier that processes an object if it
* has not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param object The pointer to the object. May be an interior pointer to a
* an interface of the actual object.
*/
static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params,
const void* object) {
internal::WriteBarrier::DijkstraMarkingBarrier(params, object);
}
/**
* Conservative Dijkstra-style write barrier that processes a range of
* elements if they have not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param first_element Pointer to the first element that should be processed.
* The slot itself must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
* \param element_size Size of the element in bytes.
* \param number_of_elements Number of elements that should be processed,
* starting with `first_element`.
* \param trace_callback The trace callback that should be invoked for each
* element if necessary.
*/
static V8_INLINE void DijkstraWriteBarrierRange(
const WriteBarrierParams& params, const void* first_element,
size_t element_size, size_t number_of_elements,
TraceCallback trace_callback) {
internal::WriteBarrier::DijkstraMarkingBarrierRange(
params, first_element, element_size, number_of_elements,
trace_callback);
}
/**
* Steele-style write barrier that re-processes an object if it has already
* been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param object The pointer to the object which must point to an object that
* has been allocated using `MakeGarbageCollected()`. Interior pointers are
* not supported.
*/
static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params,
const void* object) {
internal::WriteBarrier::SteeleMarkingBarrier(params, object);
}
/**
* Generational barrier for maintaining consistency when running with multiple
* generations.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param slot Slot containing the pointer to the object. The slot itself
* must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
*/
static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params,
const void* slot) {
internal::WriteBarrier::GenerationalBarrier<
internal::WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params,
slot);
}
/**
* Generational barrier for maintaining consistency when running with multiple
* generations. This version is used when slot contains uncompressed pointer.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param slot Uncompressed slot containing the direct pointer to the object.
* The slot itself must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
*/
static V8_INLINE void GenerationalBarrierForUncompressedSlot(
const WriteBarrierParams& params, const void* uncompressed_slot) {
internal::WriteBarrier::GenerationalBarrier<
internal::WriteBarrier::GenerationalBarrierType::
kPreciseUncompressedSlot>(params, uncompressed_slot);
}
/**
* Generational barrier for source object that may contain outgoing pointers
* to objects in young generation.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param inner_pointer Pointer to the source object.
*/
static V8_INLINE void GenerationalBarrierForSourceObject(
const WriteBarrierParams& params, const void* inner_pointer) {
internal::WriteBarrier::GenerationalBarrier<
internal::WriteBarrier::GenerationalBarrierType::kImpreciseSlot>(
params, inner_pointer);
}
private:
HeapConsistency() = delete;
};
/**
* Disallows garbage collection finalizations. Any garbage collection triggers
* result in a crash when in this scope.
*
* Note that the garbage collector already covers paths that can lead to garbage
* collections, so user code does not require checking
* `IsGarbageCollectionAllowed()` before allocations.
*/
class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final {
CPPGC_STACK_ALLOCATED();
public:
/**
* \returns whether garbage collections are currently allowed.
*/
static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle);
/**
* Enters a disallow garbage collection scope. Must be paired with `Leave()`.
* Prefer a scope instance of `DisallowGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Enter(HeapHandle& heap_handle);
/**
* Leaves a disallow garbage collection scope. Must be paired with `Enter()`.
* Prefer a scope instance of `DisallowGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Leave(HeapHandle& heap_handle);
/**
* Constructs a scoped object that automatically enters and leaves a disallow
* garbage collection scope based on its lifetime.
*
* \param heap_handle The corresponding heap.
*/
explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle);
~DisallowGarbageCollectionScope();
DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) =
delete;
DisallowGarbageCollectionScope& operator=(
const DisallowGarbageCollectionScope&) = delete;
private:
HeapHandle& heap_handle_;
};
/**
* Avoids invoking garbage collection finalizations. Already running garbage
* collection phase are unaffected by this scope.
*
* Should only be used temporarily as the scope has an impact on memory usage
* and follow up garbage collections.
*/
class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final {
CPPGC_STACK_ALLOCATED();
public:
/**
* Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer
* a scope instance of `NoGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Enter(HeapHandle& heap_handle);
/**
* Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer
* a scope instance of `NoGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Leave(HeapHandle& heap_handle);
/**
* Constructs a scoped object that automatically enters and leaves a no
* garbage collection scope based on its lifetime.
*
* \param heap_handle The corresponding heap.
*/
explicit NoGarbageCollectionScope(HeapHandle& heap_handle);
~NoGarbageCollectionScope();
NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete;
NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete;
private:
HeapHandle& heap_handle_;
};
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_

View File

@@ -0,0 +1,48 @@
// Copyright 2022 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 INCLUDE_CPPGC_HEAP_HANDLE_H_
#define INCLUDE_CPPGC_HEAP_HANDLE_H_
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class HeapBase;
class WriteBarrierTypeForCagedHeapPolicy;
class WriteBarrierTypeForNonCagedHeapPolicy;
} // namespace internal
/**
* Opaque handle used for additional heap APIs.
*/
class HeapHandle {
public:
// Deleted copy ctor to avoid treating the type by value.
HeapHandle(const HeapHandle&) = delete;
HeapHandle& operator=(const HeapHandle&) = delete;
private:
HeapHandle() = default;
V8_INLINE bool is_incremental_marking_in_progress() const {
return is_incremental_marking_in_progress_;
}
V8_INLINE bool is_young_generation_enabled() const {
return is_young_generation_enabled_;
}
bool is_incremental_marking_in_progress_ = false;
bool is_young_generation_enabled_ = false;
friend class internal::HeapBase;
friend class internal::WriteBarrierTypeForCagedHeapPolicy;
friend class internal::WriteBarrierTypeForNonCagedHeapPolicy;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_HANDLE_H_

View File

@@ -0,0 +1,82 @@
// Copyright 2021 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 INCLUDE_CPPGC_HEAP_STATE_H_
#define INCLUDE_CPPGC_HEAP_STATE_H_
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class HeapHandle;
namespace subtle {
/**
* Helpers to peek into heap-internal state.
*/
class V8_EXPORT HeapState final {
public:
/**
* Returns whether the garbage collector is marking. This API is experimental
* and is expected to be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the garbage collector is currently marking, and false
* otherwise.
*/
static bool IsMarking(const HeapHandle& heap_handle);
/*
* Returns whether the garbage collector is sweeping. This API is experimental
* and is expected to be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the garbage collector is currently sweeping, and false
* otherwise.
*/
static bool IsSweeping(const HeapHandle& heap_handle);
/*
* Returns whether the garbage collector is currently sweeping on the thread
* owning this heap. This API allows the caller to determine whether it has
* been called from a destructor of a managed object. This API is experimental
* and may be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the garbage collector is currently sweeping on this
* thread, and false otherwise.
*/
static bool IsSweepingOnOwningThread(const HeapHandle& heap_handle);
/**
* Returns whether the garbage collector is in the atomic pause, i.e., the
* mutator is stopped from running. This API is experimental and is expected
* to be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the garbage collector is currently in the atomic pause,
* and false otherwise.
*/
static bool IsInAtomicPause(const HeapHandle& heap_handle);
/**
* Returns whether the last garbage collection was finalized conservatively
* (i.e., with a non-empty stack). This API is experimental and is expected to
* be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the last garbage collection was finalized conservatively,
* and false otherwise.
*/
static bool PreviousGCWasConservative(const HeapHandle& heap_handle);
private:
HeapState() = delete;
};
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_STATE_H_

View File

@@ -0,0 +1,120 @@
// Copyright 2021 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 INCLUDE_CPPGC_HEAP_STATISTICS_H_
#define INCLUDE_CPPGC_HEAP_STATISTICS_H_
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
namespace cppgc {
/**
* `HeapStatistics` contains memory consumption and utilization statistics for a
* cppgc heap.
*/
struct HeapStatistics final {
/**
* Specifies the detail level of the heap statistics. Brief statistics contain
* only the top-level allocated and used memory statistics for the entire
* heap. Detailed statistics also contain a break down per space and page, as
* well as freelist statistics and object type histograms. Note that used
* memory reported by brief statistics and detailed statistics might differ
* slightly.
*/
enum DetailLevel : uint8_t {
kBrief,
kDetailed,
};
/**
* Object statistics for a single type.
*/
struct ObjectStatsEntry {
/**
* Number of allocated bytes.
*/
size_t allocated_bytes;
/**
* Number of allocated objects.
*/
size_t object_count;
};
/**
* Page granularity statistics. For each page the statistics record the
* allocated memory size and overall used memory size for the page.
*/
struct PageStatistics {
/** Overall committed amount of memory for the page. */
size_t committed_size_bytes = 0;
/** Resident amount of memory held by the page. */
size_t resident_size_bytes = 0;
/** Amount of memory actually used on the page. */
size_t used_size_bytes = 0;
/** Statistics for object allocated on the page. Filled only when
* NameProvider::SupportsCppClassNamesAsObjectNames() is true. */
std::vector<ObjectStatsEntry> object_statistics;
};
/**
* Statistics of the freelist (used only in non-large object spaces). For
* each bucket in the freelist the statistics record the bucket size, the
* number of freelist entries in the bucket, and the overall allocated memory
* consumed by these freelist entries.
*/
struct FreeListStatistics {
/** bucket sizes in the freelist. */
std::vector<size_t> bucket_size;
/** number of freelist entries per bucket. */
std::vector<size_t> free_count;
/** memory size consumed by freelist entries per size. */
std::vector<size_t> free_size;
};
/**
* Space granularity statistics. For each space the statistics record the
* space name, the amount of allocated memory and overall used memory for the
* space. The statistics also contain statistics for each of the space's
* pages, its freelist and the objects allocated on the space.
*/
struct SpaceStatistics {
/** The space name */
std::string name;
/** Overall committed amount of memory for the heap. */
size_t committed_size_bytes = 0;
/** Resident amount of memory held by the heap. */
size_t resident_size_bytes = 0;
/** Amount of memory actually used on the space. */
size_t used_size_bytes = 0;
/** Statistics for each of the pages in the space. */
std::vector<PageStatistics> page_stats;
/** Statistics for the freelist of the space. */
FreeListStatistics free_list_stats;
};
/** Overall committed amount of memory for the heap. */
size_t committed_size_bytes = 0;
/** Resident amount of memory held by the heap. */
size_t resident_size_bytes = 0;
/** Amount of memory actually used on the heap. */
size_t used_size_bytes = 0;
/** Detail level of this HeapStatistics. */
DetailLevel detail_level;
/** Statistics for each of the spaces in the heap. Filled only when
* `detail_level` is `DetailLevel::kDetailed`. */
std::vector<SpaceStatistics> space_stats;
/**
* Vector of `cppgc::GarbageCollected` type names.
*/
std::vector<std::string> type_names;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_STATISTICS_H_

View File

@@ -0,0 +1,202 @@
// Copyright 2020 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 INCLUDE_CPPGC_HEAP_H_
#define INCLUDE_CPPGC_HEAP_H_
#include <cstddef>
#include <cstdint>
#include <memory>
#include <vector>
#include "cppgc/common.h"
#include "cppgc/custom-space.h"
#include "cppgc/platform.h"
#include "v8config.h" // NOLINT(build/include_directory)
/**
* cppgc - A C++ garbage collection library.
*/
namespace cppgc {
class AllocationHandle;
class HeapHandle;
/**
* Implementation details of cppgc. Those details are considered internal and
* may change at any point in time without notice. Users should never rely on
* the contents of this namespace.
*/
namespace internal {
class Heap;
} // namespace internal
class V8_EXPORT Heap {
public:
/**
* Specifies the stack state the embedder is in.
*/
using StackState = EmbedderStackState;
/**
* Specifies whether conservative stack scanning is supported.
*/
enum class StackSupport : uint8_t {
/**
* Conservative stack scan is supported.
*/
kSupportsConservativeStackScan,
/**
* Conservative stack scan is not supported. Embedders may use this option
* when using custom infrastructure that is unsupported by the library.
*/
kNoConservativeStackScan,
};
/**
* Specifies supported marking types.
*/
enum class MarkingType : uint8_t {
/**
* Atomic stop-the-world marking. This option does not require any write
* barriers but is the most intrusive in terms of jank.
*/
kAtomic,
/**
* Incremental marking interleaves marking with the rest of the application
* workload on the same thread.
*/
kIncremental,
/**
* Incremental and concurrent marking.
*/
kIncrementalAndConcurrent
};
/**
* Specifies supported sweeping types.
*/
enum class SweepingType : uint8_t {
/**
* Atomic stop-the-world sweeping. All of sweeping is performed at once.
*/
kAtomic,
/**
* Incremental sweeping interleaves sweeping with the rest of the
* application workload on the same thread.
*/
kIncremental,
/**
* Incremental and concurrent sweeping. Sweeping is split and interleaved
* with the rest of the application.
*/
kIncrementalAndConcurrent
};
/**
* Constraints for a Heap setup.
*/
struct ResourceConstraints {
/**
* Allows the heap to grow to some initial size in bytes before triggering
* garbage collections. This is useful when it is known that applications
* need a certain minimum heap to run to avoid repeatedly invoking the
* garbage collector when growing the heap.
*/
size_t initial_heap_size_bytes = 0;
};
/**
* Options specifying Heap properties (e.g. custom spaces) when initializing a
* heap through `Heap::Create()`.
*/
struct HeapOptions {
/**
* Creates reasonable defaults for instantiating a Heap.
*
* \returns the HeapOptions that can be passed to `Heap::Create()`.
*/
static HeapOptions Default() { return {}; }
/**
* Custom spaces added to heap are required to have indices forming a
* numbered sequence starting at 0, i.e., their `kSpaceIndex` must
* correspond to the index they reside in the vector.
*/
std::vector<std::unique_ptr<CustomSpaceBase>> custom_spaces;
/**
* Specifies whether conservative stack scan is supported. When conservative
* stack scan is not supported, the collector may try to invoke
* garbage collections using non-nestable task, which are guaranteed to have
* no interesting stack, through the provided Platform. If such tasks are
* not supported by the Platform, the embedder must take care of invoking
* the GC through `ForceGarbageCollectionSlow()`.
*/
StackSupport stack_support = StackSupport::kSupportsConservativeStackScan;
/**
* Specifies which types of marking are supported by the heap.
*/
MarkingType marking_support = MarkingType::kIncrementalAndConcurrent;
/**
* Specifies which types of sweeping are supported by the heap.
*/
SweepingType sweeping_support = SweepingType::kIncrementalAndConcurrent;
/**
* Resource constraints specifying various properties that the internal
* GC scheduler follows.
*/
ResourceConstraints resource_constraints;
};
/**
* Creates a new heap that can be used for object allocation.
*
* \param platform implemented and provided by the embedder.
* \param options HeapOptions specifying various properties for the Heap.
* \returns a new Heap instance.
*/
static std::unique_ptr<Heap> Create(
std::shared_ptr<Platform> platform,
HeapOptions options = HeapOptions::Default());
virtual ~Heap() = default;
/**
* Forces garbage collection.
*
* \param source String specifying the source (or caller) triggering a
* forced garbage collection.
* \param reason String specifying the reason for the forced garbage
* collection.
* \param stack_state The embedder stack state, see StackState.
*/
void ForceGarbageCollectionSlow(
const char* source, const char* reason,
StackState stack_state = StackState::kMayContainHeapPointers);
/**
* \returns the opaque handle for allocating objects using
* `MakeGarbageCollected()`.
*/
AllocationHandle& GetAllocationHandle();
/**
* \returns the opaque heap handle which may be used to refer to this heap in
* other APIs. Valid as long as the underlying `Heap` is alive.
*/
HeapHandle& GetHeapHandle();
private:
Heap() = default;
friend class internal::Heap;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_H_

View File

@@ -0,0 +1,68 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_
#define INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_
#include <cstddef>
#include <cstdint>
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
// Embedders should not rely on this code!
// Internal constants to avoid exposing internal types on the API surface.
namespace api_constants {
constexpr size_t kKB = 1024;
constexpr size_t kMB = kKB * 1024;
constexpr size_t kGB = kMB * 1024;
// Offset of the uint16_t bitfield from the payload contaning the
// in-construction bit. This is subtracted from the payload pointer to get
// to the right bitfield.
static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload =
2 * sizeof(uint16_t);
// Mask for in-construction bit.
static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1};
static constexpr size_t kPageSize = size_t{1} << 17;
#if defined(V8_TARGET_ARCH_ARM64) && defined(V8_OS_DARWIN)
constexpr size_t kGuardPageSize = 0;
#else
constexpr size_t kGuardPageSize = 4096;
#endif
static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2;
#if defined(CPPGC_CAGED_HEAP)
#if defined(CPPGC_2GB_CAGE)
constexpr size_t kCagedHeapReservationSize = static_cast<size_t>(2) * kGB;
#else // !defined(CPPGC_2GB_CAGE)
constexpr size_t kCagedHeapReservationSize = static_cast<size_t>(4) * kGB;
#endif // !defined(CPPGC_2GB_CAGE)
constexpr size_t kCagedHeapReservationAlignment = kCagedHeapReservationSize;
#endif // defined(CPPGC_CAGED_HEAP)
static constexpr size_t kDefaultAlignment = sizeof(void*);
// Maximum support alignment for a type as in `alignof(T)`.
static constexpr size_t kMaxSupportedAlignment = 2 * kDefaultAlignment;
// Granularity of heap allocations.
constexpr size_t kAllocationGranularity = sizeof(void*);
// Default cacheline size.
constexpr size_t kCachelineSize = 64;
} // namespace api_constants
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_

View File

@@ -0,0 +1,48 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
#include <atomic>
namespace cppgc {
namespace internal {
// A flag which provides a fast check whether a scope may be entered on the
// current thread, without needing to access thread-local storage or mutex. Can
// have false positives (i.e., spuriously report that it might be entered), so
// it is expected that this will be used in tandem with a precise check that the
// scope is in fact entered on that thread.
//
// Example:
// g_frobnicating_flag.MightBeEntered() &&
// ThreadLocalFrobnicator().IsFrobnicating()
//
// Relaxed atomic operations are sufficient, since:
// - all accesses remain atomic
// - each thread must observe its own operations in order
// - no thread ever exits the flag more times than it enters (if used correctly)
// And so if a thread observes zero, it must be because it has observed an equal
// number of exits as entries.
class AtomicEntryFlag final {
public:
void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); }
void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); }
// Returns false only if the current thread is not between a call to Enter
// and a call to Exit. Returns true if this thread or another thread may
// currently be in the scope guarded by this flag.
bool MightBeEntered() const {
return entries_.load(std::memory_order_relaxed) != 0;
}
private:
std::atomic_int entries_{0};
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_

View File

@@ -0,0 +1,45 @@
// Copyright 2022 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 INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_
#define INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_
#include "cppgc/heap-handle.h"
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/logging.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
// The class is needed in the header to allow for fast access to HeapHandle in
// the write barrier.
class BasePageHandle {
public:
static V8_INLINE BasePageHandle* FromPayload(void* payload) {
return reinterpret_cast<BasePageHandle*>(
(reinterpret_cast<uintptr_t>(payload) &
~(api_constants::kPageSize - 1)) +
api_constants::kGuardPageSize);
}
static V8_INLINE const BasePageHandle* FromPayload(const void* payload) {
return FromPayload(const_cast<void*>(payload));
}
HeapHandle& heap_handle() { return heap_handle_; }
const HeapHandle& heap_handle() const { return heap_handle_; }
protected:
explicit BasePageHandle(HeapHandle& heap_handle) : heap_handle_(heap_handle) {
CPPGC_DCHECK(reinterpret_cast<uintptr_t>(this) % api_constants::kPageSize ==
api_constants::kGuardPageSize);
}
HeapHandle& heap_handle_;
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_

View File

@@ -0,0 +1,111 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
#include <array>
#include <cstddef>
#include <cstdint>
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/caged-heap.h"
#include "cppgc/internal/logging.h"
#include "cppgc/platform.h"
#include "v8config.h" // NOLINT(build/include_directory)
#if __cpp_lib_bitopts
#include <bit>
#endif // __cpp_lib_bitopts
#if defined(CPPGC_CAGED_HEAP)
namespace cppgc {
namespace internal {
class HeapBase;
class HeapBaseHandle;
#if defined(CPPGC_YOUNG_GENERATION)
// AgeTable is the bytemap needed for the fast generation check in the write
// barrier. AgeTable contains entries that correspond to 4096 bytes memory
// regions (cards). Each entry in the table represents generation of the objects
// that reside on the corresponding card (young, old or mixed).
class V8_EXPORT AgeTable final {
static constexpr size_t kRequiredSize = 1 * api_constants::kMB;
static constexpr size_t kAllocationGranularity =
api_constants::kAllocationGranularity;
public:
// Represents age of the objects living on a single card.
enum class Age : uint8_t { kOld, kYoung, kMixed };
// When setting age for a range, consider or ignore ages of the adjacent
// cards.
enum class AdjacentCardsPolicy : uint8_t { kConsider, kIgnore };
static constexpr size_t kCardSizeInBytes =
api_constants::kCagedHeapReservationSize / kRequiredSize;
void SetAge(uintptr_t cage_offset, Age age) {
table_[card(cage_offset)] = age;
}
V8_INLINE Age GetAge(uintptr_t cage_offset) const {
return table_[card(cage_offset)];
}
void SetAgeForRange(uintptr_t cage_offset_begin, uintptr_t cage_offset_end,
Age age, AdjacentCardsPolicy adjacent_cards_policy);
Age GetAgeForRange(uintptr_t cage_offset_begin,
uintptr_t cage_offset_end) const;
void ResetForTesting();
private:
V8_INLINE size_t card(uintptr_t offset) const {
constexpr size_t kGranularityBits =
#if __cpp_lib_bitopts
std::countr_zero(static_cast<uint32_t>(kCardSizeInBytes));
#elif V8_HAS_BUILTIN_CTZ
__builtin_ctz(static_cast<uint32_t>(kCardSizeInBytes));
#else //! V8_HAS_BUILTIN_CTZ
// Hardcode and check with assert.
#if defined(CPPGC_2GB_CAGE)
11;
#else // !defined(CPPGC_2GB_CAGE)
12;
#endif // !defined(CPPGC_2GB_CAGE)
#endif // !V8_HAS_BUILTIN_CTZ
static_assert((1 << kGranularityBits) == kCardSizeInBytes);
const size_t entry = offset >> kGranularityBits;
CPPGC_DCHECK(table_.size() > entry);
return entry;
}
std::array<Age, kRequiredSize> table_;
};
static_assert(sizeof(AgeTable) == 1 * api_constants::kMB,
"Size of AgeTable is 1MB");
#endif // CPPGC_YOUNG_GENERATION
struct CagedHeapLocalData final {
V8_INLINE static CagedHeapLocalData& Get() {
return *reinterpret_cast<CagedHeapLocalData*>(CagedHeapBase::GetBase());
}
#if defined(CPPGC_YOUNG_GENERATION)
AgeTable age_table;
#endif
};
} // namespace internal
} // namespace cppgc
#endif // defined(CPPGC_CAGED_HEAP)
#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_

View File

@@ -0,0 +1,61 @@
// Copyright 2022 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 INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_
#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_
#include <climits>
#include <cstddef>
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/base-page-handle.h"
#include "v8config.h" // NOLINT(build/include_directory)
#if defined(CPPGC_CAGED_HEAP)
namespace cppgc {
namespace internal {
class V8_EXPORT CagedHeapBase {
public:
V8_INLINE static uintptr_t OffsetFromAddress(const void* address) {
return reinterpret_cast<uintptr_t>(address) &
(api_constants::kCagedHeapReservationAlignment - 1);
}
V8_INLINE static bool IsWithinCage(const void* address) {
CPPGC_DCHECK(g_heap_base_);
return (reinterpret_cast<uintptr_t>(address) &
~(api_constants::kCagedHeapReservationAlignment - 1)) ==
g_heap_base_;
}
V8_INLINE static bool AreWithinCage(const void* addr1, const void* addr2) {
#if defined(CPPGC_2GB_CAGE)
static constexpr size_t kHalfWordShift = sizeof(uint32_t) * CHAR_BIT - 1;
#else //! defined(CPPGC_2GB_CAGE)
static constexpr size_t kHalfWordShift = sizeof(uint32_t) * CHAR_BIT;
#endif //! defined(CPPGC_2GB_CAGE)
static_assert((static_cast<size_t>(1) << kHalfWordShift) ==
api_constants::kCagedHeapReservationSize);
CPPGC_DCHECK(g_heap_base_);
return !(((reinterpret_cast<uintptr_t>(addr1) ^ g_heap_base_) |
(reinterpret_cast<uintptr_t>(addr2) ^ g_heap_base_)) >>
kHalfWordShift);
}
V8_INLINE static uintptr_t GetBase() { return g_heap_base_; }
private:
friend class CagedHeap;
static uintptr_t g_heap_base_;
};
} // namespace internal
} // namespace cppgc
#endif // defined(CPPGC_CAGED_HEAP)
#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_

View File

@@ -0,0 +1,38 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_
#define INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_
namespace cppgc {
#if defined(__has_attribute)
#define CPPGC_HAS_ATTRIBUTE(FEATURE) __has_attribute(FEATURE)
#else
#define CPPGC_HAS_ATTRIBUTE(FEATURE) 0
#endif
#if defined(__has_cpp_attribute)
#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE)
#else
#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) 0
#endif
// [[no_unique_address]] comes in C++20 but supported in clang with -std >=
// c++11.
#if CPPGC_HAS_CPP_ATTRIBUTE(no_unique_address)
#define CPPGC_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define CPPGC_NO_UNIQUE_ADDRESS
#endif
#if CPPGC_HAS_ATTRIBUTE(unused)
#define CPPGC_UNUSED __attribute__((unused))
#else
#define CPPGC_UNUSED
#endif
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_

View File

@@ -0,0 +1,93 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
#include <type_traits>
#include "cppgc/type-traits.h"
namespace cppgc {
namespace internal {
using FinalizationCallback = void (*)(void*);
template <typename T, typename = void>
struct HasFinalizeGarbageCollectedObject : std::false_type {};
template <typename T>
struct HasFinalizeGarbageCollectedObject<
T,
std::void_t<decltype(std::declval<T>().FinalizeGarbageCollectedObject())>>
: std::true_type {};
// The FinalizerTraitImpl specifies how to finalize objects.
template <typename T, bool isFinalized>
struct FinalizerTraitImpl;
template <typename T>
struct FinalizerTraitImpl<T, true> {
private:
// Dispatch to custom FinalizeGarbageCollectedObject().
struct Custom {
static void Call(void* obj) {
static_cast<T*>(obj)->FinalizeGarbageCollectedObject();
}
};
// Dispatch to regular destructor.
struct Destructor {
static void Call(void* obj) { static_cast<T*>(obj)->~T(); }
};
using FinalizeImpl =
std::conditional_t<HasFinalizeGarbageCollectedObject<T>::value, Custom,
Destructor>;
public:
static void Finalize(void* obj) {
static_assert(sizeof(T), "T must be fully defined");
FinalizeImpl::Call(obj);
}
};
template <typename T>
struct FinalizerTraitImpl<T, false> {
static void Finalize(void* obj) {
static_assert(sizeof(T), "T must be fully defined");
}
};
// The FinalizerTrait is used to determine if a type requires finalization and
// what finalization means.
template <typename T>
struct FinalizerTrait {
private:
// Object has a finalizer if it has
// - a custom FinalizeGarbageCollectedObject method, or
// - a destructor.
static constexpr bool kNonTrivialFinalizer =
internal::HasFinalizeGarbageCollectedObject<T>::value ||
!std::is_trivially_destructible<typename std::remove_cv<T>::type>::value;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
}
public:
static constexpr bool HasFinalizer() { return kNonTrivialFinalizer; }
// The callback used to finalize an object of type T.
static constexpr FinalizationCallback kCallback =
kNonTrivialFinalizer ? Finalize : nullptr;
};
template <typename T>
constexpr FinalizationCallback FinalizerTrait<T>::kCallback;
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_

View File

@@ -0,0 +1,157 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
#include <atomic>
#include <cstdint>
#include <type_traits>
#include "cppgc/internal/finalizer-trait.h"
#include "cppgc/internal/logging.h"
#include "cppgc/internal/name-trait.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
using GCInfoIndex = uint16_t;
struct V8_EXPORT EnsureGCInfoIndexTrait final {
// Acquires a new GC info object and updates `registered_index` with the index
// that identifies that new info accordingly.
template <typename T>
V8_INLINE static void EnsureIndex(
std::atomic<GCInfoIndex>& registered_index) {
EnsureGCInfoIndexTraitDispatch<T>{}(registered_index);
}
private:
template <typename T, bool = std::is_polymorphic<T>::value,
bool = FinalizerTrait<T>::HasFinalizer(),
bool = NameTrait<T>::HasNonHiddenName()>
struct EnsureGCInfoIndexTraitDispatch;
static void V8_PRESERVE_MOST
EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback,
FinalizationCallback, NameCallback);
static void V8_PRESERVE_MOST EnsureGCInfoIndexPolymorphic(
std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback);
static void V8_PRESERVE_MOST EnsureGCInfoIndexPolymorphic(
std::atomic<GCInfoIndex>&, TraceCallback, NameCallback);
static void V8_PRESERVE_MOST
EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback);
static void V8_PRESERVE_MOST
EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback,
FinalizationCallback, NameCallback);
static void V8_PRESERVE_MOST EnsureGCInfoIndexNonPolymorphic(
std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback);
static void V8_PRESERVE_MOST EnsureGCInfoIndexNonPolymorphic(
std::atomic<GCInfoIndex>&, TraceCallback, NameCallback);
static void V8_PRESERVE_MOST
EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback);
};
#define DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) \
template <typename T> \
struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \
T, is_polymorphic, has_finalizer, has_non_hidden_name> { \
V8_INLINE void operator()(std::atomic<GCInfoIndex>& registered_index) { \
function; \
} \
};
// --------------------------------------------------------------------- //
// DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function)
// --------------------------------------------------------------------- //
DISPATCH(true, true, true, //
EnsureGCInfoIndexPolymorphic(registered_index, //
TraceTrait<T>::Trace, //
FinalizerTrait<T>::kCallback, //
NameTrait<T>::GetName)) //
DISPATCH(true, true, false, //
EnsureGCInfoIndexPolymorphic(registered_index, //
TraceTrait<T>::Trace, //
FinalizerTrait<T>::kCallback)) //
DISPATCH(true, false, true, //
EnsureGCInfoIndexPolymorphic(registered_index, //
TraceTrait<T>::Trace, //
NameTrait<T>::GetName)) //
DISPATCH(true, false, false, //
EnsureGCInfoIndexPolymorphic(registered_index, //
TraceTrait<T>::Trace)) //
DISPATCH(false, true, true, //
EnsureGCInfoIndexNonPolymorphic(registered_index, //
TraceTrait<T>::Trace, //
FinalizerTrait<T>::kCallback, //
NameTrait<T>::GetName)) //
DISPATCH(false, true, false, //
EnsureGCInfoIndexNonPolymorphic(registered_index, //
TraceTrait<T>::Trace, //
FinalizerTrait<T>::kCallback)) //
DISPATCH(false, false, true, //
EnsureGCInfoIndexNonPolymorphic(registered_index, //
TraceTrait<T>::Trace, //
NameTrait<T>::GetName)) //
DISPATCH(false, false, false, //
EnsureGCInfoIndexNonPolymorphic(registered_index, //
TraceTrait<T>::Trace)) //
#undef DISPATCH
// Fold types based on finalizer behavior. Note that finalizer characteristics
// align with trace behavior, i.e., destructors are virtual when trace methods
// are and vice versa.
template <typename T, typename ParentMostGarbageCollectedType>
struct GCInfoFolding {
static constexpr bool kHasVirtualDestructorAtBase =
std::has_virtual_destructor<ParentMostGarbageCollectedType>::value;
static constexpr bool kBothTypesAreTriviallyDestructible =
std::is_trivially_destructible<ParentMostGarbageCollectedType>::value &&
std::is_trivially_destructible<T>::value;
static constexpr bool kHasCustomFinalizerDispatchAtBase =
internal::HasFinalizeGarbageCollectedObject<
ParentMostGarbageCollectedType>::value;
#ifdef CPPGC_SUPPORTS_OBJECT_NAMES
static constexpr bool kWantsDetailedObjectNames = true;
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
static constexpr bool kWantsDetailedObjectNames = false;
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
// Folding would regresses name resolution when deriving names from C++
// class names as it would just folds a name to the base class name.
using ResultType = std::conditional_t<(kHasVirtualDestructorAtBase ||
kBothTypesAreTriviallyDestructible ||
kHasCustomFinalizerDispatchAtBase) &&
!kWantsDetailedObjectNames,
ParentMostGarbageCollectedType, T>;
};
// Trait determines how the garbage collector treats objects wrt. to traversing,
// finalization, and naming.
template <typename T>
struct GCInfoTrait final {
V8_INLINE static GCInfoIndex Index() {
static_assert(sizeof(T), "T must be fully defined");
static std::atomic<GCInfoIndex>
registered_index; // Uses zero initialization.
GCInfoIndex index = registered_index.load(std::memory_order_acquire);
if (V8_UNLIKELY(!index)) {
EnsureGCInfoIndexTrait::EnsureIndex<T>(registered_index);
// Slow path call uses V8_PRESERVE_MOST which does not support return
// values (also preserves RAX). Avoid out parameter by just reloading the
// value here which at this point is guaranteed to be set.
index = registered_index.load(std::memory_order_acquire);
CPPGC_DCHECK(index != 0);
}
return index;
}
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_

View File

@@ -0,0 +1,50 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_LOGGING_H_
#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_
#include "cppgc/source-location.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
void V8_EXPORT DCheckImpl(const char*,
const SourceLocation& = SourceLocation::Current());
[[noreturn]] void V8_EXPORT
FatalImpl(const char*, const SourceLocation& = SourceLocation::Current());
// Used to ignore -Wunused-variable.
template <typename>
struct EatParams {};
#if defined(DEBUG)
#define CPPGC_DCHECK_MSG(condition, message) \
do { \
if (V8_UNLIKELY(!(condition))) { \
::cppgc::internal::DCheckImpl(message); \
} \
} while (false)
#else // !defined(DEBUG)
#define CPPGC_DCHECK_MSG(condition, message) \
(static_cast<void>(::cppgc::internal::EatParams<decltype( \
static_cast<void>(condition), message)>{}))
#endif // !defined(DEBUG)
#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition)
#define CPPGC_CHECK_MSG(condition, message) \
do { \
if (V8_UNLIKELY(!(condition))) { \
::cppgc::internal::FatalImpl(message); \
} \
} while (false)
#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition)
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_

View File

@@ -0,0 +1,248 @@
// Copyright 2022 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 INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_
#define INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_
#include <atomic>
#include <cstddef>
#include <type_traits>
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/logging.h"
#include "cppgc/sentinel-pointer.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
enum class WriteBarrierSlotType {
kCompressed,
kUncompressed,
};
#if defined(CPPGC_POINTER_COMPRESSION)
#if defined(__clang__)
// Attribute const allows the compiler to assume that CageBaseGlobal::g_base_
// doesn't change (e.g. across calls) and thereby avoid redundant loads.
#define CPPGC_CONST __attribute__((const))
#define CPPGC_REQUIRE_CONSTANT_INIT \
__attribute__((require_constant_initialization))
#else // defined(__clang__)
#define CPPGC_CONST
#define CPPGC_REQUIRE_CONSTANT_INIT
#endif // defined(__clang__)
class V8_EXPORT CageBaseGlobal final {
public:
V8_INLINE CPPGC_CONST static uintptr_t Get() {
CPPGC_DCHECK(IsBaseConsistent());
return g_base_.base;
}
V8_INLINE CPPGC_CONST static bool IsSet() {
CPPGC_DCHECK(IsBaseConsistent());
return (g_base_.base & ~kLowerHalfWordMask) != 0;
}
private:
// We keep the lower halfword as ones to speed up decompression.
static constexpr uintptr_t kLowerHalfWordMask =
(api_constants::kCagedHeapReservationAlignment - 1);
static union alignas(api_constants::kCachelineSize) Base {
uintptr_t base;
char cache_line[api_constants::kCachelineSize];
} g_base_ CPPGC_REQUIRE_CONSTANT_INIT;
CageBaseGlobal() = delete;
V8_INLINE static bool IsBaseConsistent() {
return kLowerHalfWordMask == (g_base_.base & kLowerHalfWordMask);
}
friend class CageBaseGlobalUpdater;
};
#undef CPPGC_REQUIRE_CONSTANT_INIT
#undef CPPGC_CONST
class V8_TRIVIAL_ABI CompressedPointer final {
public:
using IntegralType = uint32_t;
static constexpr auto kWriteBarrierSlotType =
WriteBarrierSlotType::kCompressed;
V8_INLINE CompressedPointer() : value_(0u) {}
V8_INLINE explicit CompressedPointer(const void* ptr)
: value_(Compress(ptr)) {}
V8_INLINE explicit CompressedPointer(std::nullptr_t) : value_(0u) {}
V8_INLINE explicit CompressedPointer(SentinelPointer)
: value_(kCompressedSentinel) {}
V8_INLINE const void* Load() const { return Decompress(value_); }
V8_INLINE const void* LoadAtomic() const {
return Decompress(
reinterpret_cast<const std::atomic<IntegralType>&>(value_).load(
std::memory_order_relaxed));
}
V8_INLINE void Store(const void* ptr) { value_ = Compress(ptr); }
V8_INLINE void StoreAtomic(const void* value) {
reinterpret_cast<std::atomic<IntegralType>&>(value_).store(
Compress(value), std::memory_order_relaxed);
}
V8_INLINE void Clear() { value_ = 0u; }
V8_INLINE bool IsCleared() const { return !value_; }
V8_INLINE bool IsSentinel() const { return value_ == kCompressedSentinel; }
V8_INLINE uint32_t GetAsInteger() const { return value_; }
V8_INLINE friend bool operator==(CompressedPointer a, CompressedPointer b) {
return a.value_ == b.value_;
}
V8_INLINE friend bool operator!=(CompressedPointer a, CompressedPointer b) {
return a.value_ != b.value_;
}
V8_INLINE friend bool operator<(CompressedPointer a, CompressedPointer b) {
return a.value_ < b.value_;
}
V8_INLINE friend bool operator<=(CompressedPointer a, CompressedPointer b) {
return a.value_ <= b.value_;
}
V8_INLINE friend bool operator>(CompressedPointer a, CompressedPointer b) {
return a.value_ > b.value_;
}
V8_INLINE friend bool operator>=(CompressedPointer a, CompressedPointer b) {
return a.value_ >= b.value_;
}
static V8_INLINE IntegralType Compress(const void* ptr) {
static_assert(
SentinelPointer::kSentinelValue == 0b10,
"The compression scheme relies on the sentinel encoded as 0b10");
static constexpr size_t kGigaCageMask =
~(api_constants::kCagedHeapReservationAlignment - 1);
CPPGC_DCHECK(CageBaseGlobal::IsSet());
const uintptr_t base = CageBaseGlobal::Get();
CPPGC_DCHECK(!ptr || ptr == kSentinelPointer ||
(base & kGigaCageMask) ==
(reinterpret_cast<uintptr_t>(ptr) & kGigaCageMask));
#if defined(CPPGC_2GB_CAGE)
// Truncate the pointer.
auto compressed =
static_cast<IntegralType>(reinterpret_cast<uintptr_t>(ptr));
#else // !defined(CPPGC_2GB_CAGE)
const auto uptr = reinterpret_cast<uintptr_t>(ptr);
// Shift the pointer by one and truncate.
auto compressed = static_cast<IntegralType>(uptr >> 1);
#endif // !defined(CPPGC_2GB_CAGE)
// Normal compressed pointers must have the MSB set.
CPPGC_DCHECK((!compressed || compressed == kCompressedSentinel) ||
(compressed & (1 << 31)));
return compressed;
}
static V8_INLINE void* Decompress(IntegralType ptr) {
CPPGC_DCHECK(CageBaseGlobal::IsSet());
const uintptr_t base = CageBaseGlobal::Get();
// Treat compressed pointer as signed and cast it to uint64_t, which will
// sign-extend it.
#if defined(CPPGC_2GB_CAGE)
const uint64_t mask = static_cast<uint64_t>(static_cast<int32_t>(ptr));
#else // !defined(CPPGC_2GB_CAGE)
// Then, shift the result by one. It's important to shift the unsigned
// value, as otherwise it would result in undefined behavior.
const uint64_t mask = static_cast<uint64_t>(static_cast<int32_t>(ptr)) << 1;
#endif // !defined(CPPGC_2GB_CAGE)
return reinterpret_cast<void*>(mask & base);
}
private:
#if defined(CPPGC_2GB_CAGE)
static constexpr IntegralType kCompressedSentinel =
SentinelPointer::kSentinelValue;
#else // !defined(CPPGC_2GB_CAGE)
static constexpr IntegralType kCompressedSentinel =
SentinelPointer::kSentinelValue >> 1;
#endif // !defined(CPPGC_2GB_CAGE)
// All constructors initialize `value_`. Do not add a default value here as it
// results in a non-atomic write on some builds, even when the atomic version
// of the constructor is used.
IntegralType value_;
};
#endif // defined(CPPGC_POINTER_COMPRESSION)
class V8_TRIVIAL_ABI RawPointer final {
public:
using IntegralType = uintptr_t;
static constexpr auto kWriteBarrierSlotType =
WriteBarrierSlotType::kUncompressed;
V8_INLINE RawPointer() : ptr_(nullptr) {}
V8_INLINE explicit RawPointer(const void* ptr) : ptr_(ptr) {}
V8_INLINE const void* Load() const { return ptr_; }
V8_INLINE const void* LoadAtomic() const {
return reinterpret_cast<const std::atomic<const void*>&>(ptr_).load(
std::memory_order_relaxed);
}
V8_INLINE void Store(const void* ptr) { ptr_ = ptr; }
V8_INLINE void StoreAtomic(const void* ptr) {
reinterpret_cast<std::atomic<const void*>&>(ptr_).store(
ptr, std::memory_order_relaxed);
}
V8_INLINE void Clear() { ptr_ = nullptr; }
V8_INLINE bool IsCleared() const { return !ptr_; }
V8_INLINE bool IsSentinel() const { return ptr_ == kSentinelPointer; }
V8_INLINE uintptr_t GetAsInteger() const {
return reinterpret_cast<uintptr_t>(ptr_);
}
V8_INLINE friend bool operator==(RawPointer a, RawPointer b) {
return a.ptr_ == b.ptr_;
}
V8_INLINE friend bool operator!=(RawPointer a, RawPointer b) {
return a.ptr_ != b.ptr_;
}
V8_INLINE friend bool operator<(RawPointer a, RawPointer b) {
return a.ptr_ < b.ptr_;
}
V8_INLINE friend bool operator<=(RawPointer a, RawPointer b) {
return a.ptr_ <= b.ptr_;
}
V8_INLINE friend bool operator>(RawPointer a, RawPointer b) {
return a.ptr_ > b.ptr_;
}
V8_INLINE friend bool operator>=(RawPointer a, RawPointer b) {
return a.ptr_ >= b.ptr_;
}
private:
// All constructors initialize `ptr_`. Do not add a default value here as it
// results in a non-atomic write on some builds, even when the atomic version
// of the constructor is used.
const void* ptr_;
};
#if defined(CPPGC_POINTER_COMPRESSION)
using DefaultMemberStorage = CompressedPointer;
#else // !defined(CPPGC_POINTER_COMPRESSION)
using DefaultMemberStorage = RawPointer;
#endif // !defined(CPPGC_POINTER_COMPRESSION)
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_

View File

@@ -0,0 +1,137 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_
#define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "cppgc/name-provider.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
#if CPPGC_SUPPORTS_OBJECT_NAMES && defined(__clang__)
#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 1
// Provides constexpr c-string storage for a name of fixed |Size| characters.
// Automatically appends terminating 0 byte.
template <size_t Size>
struct NameBuffer {
char name[Size + 1]{};
static constexpr NameBuffer FromCString(const char* str) {
NameBuffer result;
for (size_t i = 0; i < Size; ++i) result.name[i] = str[i];
result.name[Size] = 0;
return result;
}
};
template <typename T>
const char* GetTypename() {
static constexpr char kSelfPrefix[] =
"const char *cppgc::internal::GetTypename() [T =";
static_assert(__builtin_strncmp(__PRETTY_FUNCTION__, kSelfPrefix,
sizeof(kSelfPrefix) - 1) == 0,
"The prefix must match");
static constexpr const char* kTypenameStart =
__PRETTY_FUNCTION__ + sizeof(kSelfPrefix);
static constexpr size_t kTypenameSize =
__builtin_strlen(__PRETTY_FUNCTION__) - sizeof(kSelfPrefix) - 1;
// NameBuffer is an indirection that is needed to make sure that only a
// substring of __PRETTY_FUNCTION__ gets materialized in the binary.
static constexpr auto buffer =
NameBuffer<kTypenameSize>::FromCString(kTypenameStart);
return buffer.name;
}
#else
#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 0
#endif
struct HeapObjectName {
const char* value;
bool name_was_hidden;
};
enum class HeapObjectNameForUnnamedObject : uint8_t {
kUseClassNameIfSupported,
kUseHiddenName,
};
class V8_EXPORT NameTraitBase {
protected:
static HeapObjectName GetNameFromTypeSignature(const char*);
};
// Trait that specifies how the garbage collector retrieves the name for a
// given object.
template <typename T>
class NameTrait final : public NameTraitBase {
public:
static constexpr bool HasNonHiddenName() {
#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
return true;
#elif CPPGC_SUPPORTS_OBJECT_NAMES
return true;
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
return std::is_base_of<NameProvider, T>::value;
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
}
static HeapObjectName GetName(
const void* obj, HeapObjectNameForUnnamedObject name_retrieval_mode) {
return GetNameFor(static_cast<const T*>(obj), name_retrieval_mode);
}
private:
static HeapObjectName GetNameFor(const NameProvider* name_provider,
HeapObjectNameForUnnamedObject) {
// Objects inheriting from `NameProvider` are not considered unnamed as
// users already provided a name for them.
return {name_provider->GetHumanReadableName(), false};
}
static HeapObjectName GetNameFor(
const void*, HeapObjectNameForUnnamedObject name_retrieval_mode) {
if (name_retrieval_mode == HeapObjectNameForUnnamedObject::kUseHiddenName)
return {NameProvider::kHiddenName, true};
#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
return {GetTypename<T>(), false};
#elif CPPGC_SUPPORTS_OBJECT_NAMES
#if defined(V8_CC_GNU)
#define PRETTY_FUNCTION_VALUE __PRETTY_FUNCTION__
#elif defined(V8_CC_MSVC)
#define PRETTY_FUNCTION_VALUE __FUNCSIG__
#else
#define PRETTY_FUNCTION_VALUE nullptr
#endif
static const HeapObjectName leaky_name =
GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE);
return leaky_name;
#undef PRETTY_FUNCTION_VALUE
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
return {NameProvider::kHiddenName, true};
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
}
};
using NameCallback = HeapObjectName (*)(const void*,
HeapObjectNameForUnnamedObject);
} // namespace internal
} // namespace cppgc
#undef CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
#endif // INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_

View File

@@ -0,0 +1,214 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
#include <array>
#include <memory>
#include <vector>
#include "cppgc/internal/logging.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class CrossThreadPersistentRegion;
class FatalOutOfMemoryHandler;
class RootVisitor;
// PersistentNode represents a variant of two states:
// 1) traceable node with a back pointer to the Persistent object;
// 2) freelist entry.
class PersistentNode final {
public:
PersistentNode() = default;
PersistentNode(const PersistentNode&) = delete;
PersistentNode& operator=(const PersistentNode&) = delete;
void InitializeAsUsedNode(void* owner, TraceRootCallback trace) {
CPPGC_DCHECK(trace);
owner_ = owner;
trace_ = trace;
}
void InitializeAsFreeNode(PersistentNode* next) {
next_ = next;
trace_ = nullptr;
}
void UpdateOwner(void* owner) {
CPPGC_DCHECK(IsUsed());
owner_ = owner;
}
PersistentNode* FreeListNext() const {
CPPGC_DCHECK(!IsUsed());
return next_;
}
void Trace(RootVisitor& root_visitor) const {
CPPGC_DCHECK(IsUsed());
trace_(root_visitor, owner_);
}
bool IsUsed() const { return trace_; }
void* owner() const {
CPPGC_DCHECK(IsUsed());
return owner_;
}
private:
// PersistentNode acts as a designated union:
// If trace_ != nullptr, owner_ points to the corresponding Persistent handle.
// Otherwise, next_ points to the next freed PersistentNode.
union {
void* owner_ = nullptr;
PersistentNode* next_;
};
TraceRootCallback trace_ = nullptr;
};
class V8_EXPORT PersistentRegionBase {
using PersistentNodeSlots = std::array<PersistentNode, 256u>;
public:
// Clears Persistent fields to avoid stale pointers after heap teardown.
~PersistentRegionBase();
PersistentRegionBase(const PersistentRegionBase&) = delete;
PersistentRegionBase& operator=(const PersistentRegionBase&) = delete;
void Iterate(RootVisitor&);
size_t NodesInUse() const;
void ClearAllUsedNodes();
protected:
explicit PersistentRegionBase(const FatalOutOfMemoryHandler& oom_handler);
PersistentNode* TryAllocateNodeFromFreeList(void* owner,
TraceRootCallback trace) {
PersistentNode* node = nullptr;
if (V8_LIKELY(free_list_head_)) {
node = free_list_head_;
free_list_head_ = free_list_head_->FreeListNext();
CPPGC_DCHECK(!node->IsUsed());
node->InitializeAsUsedNode(owner, trace);
nodes_in_use_++;
}
return node;
}
void FreeNode(PersistentNode* node) {
CPPGC_DCHECK(node);
CPPGC_DCHECK(node->IsUsed());
node->InitializeAsFreeNode(free_list_head_);
free_list_head_ = node;
CPPGC_DCHECK(nodes_in_use_ > 0);
nodes_in_use_--;
}
PersistentNode* RefillFreeListAndAllocateNode(void* owner,
TraceRootCallback trace);
private:
template <typename PersistentBaseClass>
void ClearAllUsedNodes();
void RefillFreeList();
std::vector<std::unique_ptr<PersistentNodeSlots>> nodes_;
PersistentNode* free_list_head_ = nullptr;
size_t nodes_in_use_ = 0;
const FatalOutOfMemoryHandler& oom_handler_;
friend class CrossThreadPersistentRegion;
};
// Variant of PersistentRegionBase that checks whether the allocation and
// freeing happens only on the thread that created the region.
class V8_EXPORT PersistentRegion final : public PersistentRegionBase {
public:
explicit PersistentRegion(const FatalOutOfMemoryHandler&);
// Clears Persistent fields to avoid stale pointers after heap teardown.
~PersistentRegion() = default;
PersistentRegion(const PersistentRegion&) = delete;
PersistentRegion& operator=(const PersistentRegion&) = delete;
V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) {
CPPGC_DCHECK(IsCreationThread());
auto* node = TryAllocateNodeFromFreeList(owner, trace);
if (V8_LIKELY(node)) return node;
// Slow path allocation allows for checking thread correspondence.
CPPGC_CHECK(IsCreationThread());
return RefillFreeListAndAllocateNode(owner, trace);
}
V8_INLINE void FreeNode(PersistentNode* node) {
CPPGC_DCHECK(IsCreationThread());
PersistentRegionBase::FreeNode(node);
}
private:
bool IsCreationThread();
int creation_thread_id_;
};
// CrossThreadPersistent uses PersistentRegionBase but protects it using this
// lock when needed.
class V8_EXPORT PersistentRegionLock final {
public:
PersistentRegionLock();
~PersistentRegionLock();
static void AssertLocked();
};
// Variant of PersistentRegionBase that checks whether the PersistentRegionLock
// is locked.
class V8_EXPORT CrossThreadPersistentRegion final
: protected PersistentRegionBase {
public:
explicit CrossThreadPersistentRegion(const FatalOutOfMemoryHandler&);
// Clears Persistent fields to avoid stale pointers after heap teardown.
~CrossThreadPersistentRegion();
CrossThreadPersistentRegion(const CrossThreadPersistentRegion&) = delete;
CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) =
delete;
V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) {
PersistentRegionLock::AssertLocked();
auto* node = TryAllocateNodeFromFreeList(owner, trace);
if (V8_LIKELY(node)) return node;
return RefillFreeListAndAllocateNode(owner, trace);
}
V8_INLINE void FreeNode(PersistentNode* node) {
PersistentRegionLock::AssertLocked();
PersistentRegionBase::FreeNode(node);
}
void Iterate(RootVisitor&);
size_t NodesInUse() const;
void ClearAllUsedNodes();
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_

View File

@@ -0,0 +1,243 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
#include <cstdint>
#include <type_traits>
#include "cppgc/internal/member-storage.h"
#include "cppgc/internal/write-barrier.h"
#include "cppgc/sentinel-pointer.h"
#include "cppgc/source-location.h"
#include "cppgc/type-traits.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class HeapBase;
class PersistentRegion;
class CrossThreadPersistentRegion;
// Tags to distinguish between strong and weak member types.
class StrongMemberTag;
class WeakMemberTag;
class UntracedMemberTag;
struct DijkstraWriteBarrierPolicy {
V8_INLINE static void InitializingBarrier(const void*, const void*) {
// Since in initializing writes the source object is always white, having no
// barrier doesn't break the tri-color invariant.
}
template <WriteBarrierSlotType SlotType>
V8_INLINE static void AssigningBarrier(const void* slot, const void* value) {
#ifdef CPPGC_SLIM_WRITE_BARRIER
if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
#else // !CPPGC_SLIM_WRITE_BARRIER
WriteBarrier::Params params;
const WriteBarrier::Type type =
WriteBarrier::GetWriteBarrierType(slot, value, params);
WriteBarrier(type, params, slot, value);
#endif // !CPPGC_SLIM_WRITE_BARRIER
}
template <WriteBarrierSlotType SlotType>
V8_INLINE static void AssigningBarrier(const void* slot, RawPointer storage) {
static_assert(
SlotType == WriteBarrierSlotType::kUncompressed,
"Assigning storages of Member and UncompressedMember is not supported");
#ifdef CPPGC_SLIM_WRITE_BARRIER
if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
#else // !CPPGC_SLIM_WRITE_BARRIER
WriteBarrier::Params params;
const WriteBarrier::Type type =
WriteBarrier::GetWriteBarrierType(slot, storage, params);
WriteBarrier(type, params, slot, storage.Load());
#endif // !CPPGC_SLIM_WRITE_BARRIER
}
#if defined(CPPGC_POINTER_COMPRESSION)
template <WriteBarrierSlotType SlotType>
V8_INLINE static void AssigningBarrier(const void* slot,
CompressedPointer storage) {
static_assert(
SlotType == WriteBarrierSlotType::kCompressed,
"Assigning storages of Member and UncompressedMember is not supported");
#ifdef CPPGC_SLIM_WRITE_BARRIER
if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
#else // !CPPGC_SLIM_WRITE_BARRIER
WriteBarrier::Params params;
const WriteBarrier::Type type =
WriteBarrier::GetWriteBarrierType(slot, storage, params);
WriteBarrier(type, params, slot, storage.Load());
#endif // !CPPGC_SLIM_WRITE_BARRIER
}
#endif // defined(CPPGC_POINTER_COMPRESSION)
private:
V8_INLINE static void WriteBarrier(WriteBarrier::Type type,
const WriteBarrier::Params& params,
const void* slot, const void* value) {
switch (type) {
case WriteBarrier::Type::kGenerational:
WriteBarrier::GenerationalBarrier<
WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, slot);
break;
case WriteBarrier::Type::kMarking:
WriteBarrier::DijkstraMarkingBarrier(params, value);
break;
case WriteBarrier::Type::kNone:
break;
}
}
};
struct NoWriteBarrierPolicy {
V8_INLINE static void InitializingBarrier(const void*, const void*) {}
template <WriteBarrierSlotType>
V8_INLINE static void AssigningBarrier(const void*, const void*) {}
template <WriteBarrierSlotType, typename MemberStorage>
V8_INLINE static void AssigningBarrier(const void*, MemberStorage) {}
};
class V8_EXPORT SameThreadEnabledCheckingPolicyBase {
protected:
void CheckPointerImpl(const void* ptr, bool points_to_payload,
bool check_off_heap_assignments);
const HeapBase* heap_ = nullptr;
};
template <bool kCheckOffHeapAssignments>
class V8_EXPORT SameThreadEnabledCheckingPolicy
: private SameThreadEnabledCheckingPolicyBase {
protected:
template <typename T>
void CheckPointer(const T* ptr) {
if (!ptr || (kSentinelPointer == ptr)) return;
CheckPointersImplTrampoline<T>::Call(this, ptr);
}
private:
template <typename T, bool = IsCompleteV<T>>
struct CheckPointersImplTrampoline {
static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) {
policy->CheckPointerImpl(ptr, false, kCheckOffHeapAssignments);
}
};
template <typename T>
struct CheckPointersImplTrampoline<T, true> {
static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) {
policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV<T>,
kCheckOffHeapAssignments);
}
};
};
class DisabledCheckingPolicy {
protected:
V8_INLINE void CheckPointer(const void*) {}
};
#ifdef DEBUG
// Off heap members are not connected to object graph and thus cannot ressurect
// dead objects.
using DefaultMemberCheckingPolicy =
SameThreadEnabledCheckingPolicy<false /* kCheckOffHeapAssignments*/>;
using DefaultPersistentCheckingPolicy =
SameThreadEnabledCheckingPolicy<true /* kCheckOffHeapAssignments*/>;
#else // !DEBUG
using DefaultMemberCheckingPolicy = DisabledCheckingPolicy;
using DefaultPersistentCheckingPolicy = DisabledCheckingPolicy;
#endif // !DEBUG
// For CT(W)P neither marking information (for value), nor objectstart bitmap
// (for slot) are guaranteed to be present because there's no synchronization
// between heaps after marking.
using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy;
class KeepLocationPolicy {
public:
constexpr const SourceLocation& Location() const { return location_; }
protected:
constexpr KeepLocationPolicy() = default;
constexpr explicit KeepLocationPolicy(const SourceLocation& location)
: location_(location) {}
// KeepLocationPolicy must not copy underlying source locations.
KeepLocationPolicy(const KeepLocationPolicy&) = delete;
KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete;
// Location of the original moved from object should be preserved.
KeepLocationPolicy(KeepLocationPolicy&&) = default;
KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default;
private:
SourceLocation location_;
};
class IgnoreLocationPolicy {
public:
constexpr SourceLocation Location() const { return {}; }
protected:
constexpr IgnoreLocationPolicy() = default;
constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {}
};
#if CPPGC_SUPPORTS_OBJECT_NAMES
using DefaultLocationPolicy = KeepLocationPolicy;
#else
using DefaultLocationPolicy = IgnoreLocationPolicy;
#endif
struct StrongPersistentPolicy {
using IsStrongPersistent = std::true_type;
static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
};
struct WeakPersistentPolicy {
using IsStrongPersistent = std::false_type;
static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
};
struct StrongCrossThreadPersistentPolicy {
using IsStrongPersistent = std::true_type;
static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
const void* object);
};
struct WeakCrossThreadPersistentPolicy {
using IsStrongPersistent = std::false_type;
static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
const void* object);
};
// Forward declarations setting up the default policies.
template <typename T, typename WeaknessPolicy,
typename LocationPolicy = DefaultLocationPolicy,
typename CheckingPolicy = DefaultCrossThreadPersistentCheckingPolicy>
class BasicCrossThreadPersistent;
template <typename T, typename WeaknessPolicy,
typename LocationPolicy = DefaultLocationPolicy,
typename CheckingPolicy = DefaultPersistentCheckingPolicy>
class BasicPersistent;
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy = DefaultMemberCheckingPolicy,
typename StorageType = DefaultMemberStorage>
class BasicMember;
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_

View File

@@ -0,0 +1,487 @@
// Copyright 2020 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 INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
#include <cstddef>
#include <cstdint>
#include "cppgc/heap-handle.h"
#include "cppgc/heap-state.h"
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/atomic-entry-flag.h"
#include "cppgc/internal/base-page-handle.h"
#include "cppgc/internal/member-storage.h"
#include "cppgc/platform.h"
#include "cppgc/sentinel-pointer.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
#if defined(CPPGC_CAGED_HEAP)
#include "cppgc/internal/caged-heap-local-data.h"
#include "cppgc/internal/caged-heap.h"
#endif
namespace cppgc {
class HeapHandle;
namespace internal {
#if defined(CPPGC_CAGED_HEAP)
class WriteBarrierTypeForCagedHeapPolicy;
#else // !CPPGC_CAGED_HEAP
class WriteBarrierTypeForNonCagedHeapPolicy;
#endif // !CPPGC_CAGED_HEAP
class V8_EXPORT WriteBarrier final {
public:
enum class Type : uint8_t {
kNone,
kMarking,
kGenerational,
};
enum class GenerationalBarrierType : uint8_t {
kPreciseSlot,
kPreciseUncompressedSlot,
kImpreciseSlot,
};
struct Params {
HeapHandle* heap = nullptr;
#if V8_ENABLE_CHECKS
Type type = Type::kNone;
#endif // !V8_ENABLE_CHECKS
#if defined(CPPGC_CAGED_HEAP)
uintptr_t slot_offset = 0;
uintptr_t value_offset = 0;
#endif // CPPGC_CAGED_HEAP
};
enum class ValueMode {
kValuePresent,
kNoValuePresent,
};
// Returns the required write barrier for a given `slot` and `value`.
static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value,
Params& params);
// Returns the required write barrier for a given `slot` and `value`.
template <typename MemberStorage>
static V8_INLINE Type GetWriteBarrierType(const void* slot, MemberStorage,
Params& params);
// Returns the required write barrier for a given `slot`.
template <typename HeapHandleCallback>
static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params,
HeapHandleCallback callback);
// Returns the required write barrier for a given `value`.
static V8_INLINE Type GetWriteBarrierType(const void* value, Params& params);
#ifdef CPPGC_SLIM_WRITE_BARRIER
// A write barrier that combines `GenerationalBarrier()` and
// `DijkstraMarkingBarrier()`. We only pass a single parameter here to clobber
// as few registers as possible.
template <WriteBarrierSlotType>
static V8_NOINLINE void V8_PRESERVE_MOST
CombinedWriteBarrierSlow(const void* slot);
#endif // CPPGC_SLIM_WRITE_BARRIER
static V8_INLINE void DijkstraMarkingBarrier(const Params& params,
const void* object);
static V8_INLINE void DijkstraMarkingBarrierRange(
const Params& params, const void* first_element, size_t element_size,
size_t number_of_elements, TraceCallback trace_callback);
static V8_INLINE void SteeleMarkingBarrier(const Params& params,
const void* object);
#if defined(CPPGC_YOUNG_GENERATION)
template <GenerationalBarrierType>
static V8_INLINE void GenerationalBarrier(const Params& params,
const void* slot);
#else // !CPPGC_YOUNG_GENERATION
template <GenerationalBarrierType>
static V8_INLINE void GenerationalBarrier(const Params& params,
const void* slot){}
#endif // CPPGC_YOUNG_GENERATION
#if V8_ENABLE_CHECKS
static void CheckParams(Type expected_type, const Params& params);
#else // !V8_ENABLE_CHECKS
static void CheckParams(Type expected_type, const Params& params) {}
#endif // !V8_ENABLE_CHECKS
// The FlagUpdater class allows cppgc internal to update
// |write_barrier_enabled_|.
class FlagUpdater;
static bool IsEnabled() { return write_barrier_enabled_.MightBeEntered(); }
private:
WriteBarrier() = delete;
#if defined(CPPGC_CAGED_HEAP)
using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy;
#else // !CPPGC_CAGED_HEAP
using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy;
#endif // !CPPGC_CAGED_HEAP
static void DijkstraMarkingBarrierSlow(const void* value);
static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value);
static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle,
const void* first_element,
size_t element_size,
size_t number_of_elements,
TraceCallback trace_callback);
static void SteeleMarkingBarrierSlow(const void* value);
static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value);
#if defined(CPPGC_YOUNG_GENERATION)
static CagedHeapLocalData& GetLocalData(HeapHandle&);
static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data,
const AgeTable& age_table,
const void* slot, uintptr_t value_offset,
HeapHandle* heap_handle);
static void GenerationalBarrierForUncompressedSlotSlow(
const CagedHeapLocalData& local_data, const AgeTable& age_table,
const void* slot, uintptr_t value_offset, HeapHandle* heap_handle);
static void GenerationalBarrierForSourceObjectSlow(
const CagedHeapLocalData& local_data, const void* object,
HeapHandle* heap_handle);
#endif // CPPGC_YOUNG_GENERATION
static AtomicEntryFlag write_barrier_enabled_;
};
template <WriteBarrier::Type type>
V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) {
if constexpr (type == WriteBarrier::Type::kNone)
return WriteBarrier::Type::kNone;
#if V8_ENABLE_CHECKS
params.type = type;
#endif // !V8_ENABLE_CHECKS
return type;
}
#if defined(CPPGC_CAGED_HEAP)
class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final {
public:
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
}
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback,
typename MemberStorage>
static V8_INLINE WriteBarrier::Type Get(const void* slot, MemberStorage value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
}
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
return GetNoSlot(value, params, callback);
}
private:
WriteBarrierTypeForCagedHeapPolicy() = delete;
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value,
WriteBarrier::Params& params,
HeapHandleCallback) {
const bool within_cage = CagedHeapBase::IsWithinCage(value);
if (!within_cage) return WriteBarrier::Type::kNone;
// We know that |value| points either within the normal page or to the
// beginning of large-page, so extract the page header by bitmasking.
BasePageHandle* page =
BasePageHandle::FromPayload(const_cast<void*>(value));
HeapHandle& heap_handle = page->heap_handle();
if (V8_UNLIKELY(heap_handle.is_incremental_marking_in_progress())) {
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
template <WriteBarrier::ValueMode value_mode>
struct ValueModeDispatch;
};
template <>
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kValuePresent> {
template <typename HeapHandleCallback, typename MemberStorage>
static V8_INLINE WriteBarrier::Type Get(const void* slot,
MemberStorage storage,
WriteBarrier::Params& params,
HeapHandleCallback) {
if (V8_LIKELY(!WriteBarrier::IsEnabled()))
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
return BarrierEnabledGet(slot, storage.Load(), params);
}
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
WriteBarrier::Params& params,
HeapHandleCallback) {
if (V8_LIKELY(!WriteBarrier::IsEnabled()))
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
return BarrierEnabledGet(slot, value, params);
}
private:
static V8_INLINE WriteBarrier::Type BarrierEnabledGet(
const void* slot, const void* value, WriteBarrier::Params& params) {
const bool within_cage = CagedHeapBase::AreWithinCage(slot, value);
if (!within_cage) return WriteBarrier::Type::kNone;
// We know that |value| points either within the normal page or to the
// beginning of large-page, so extract the page header by bitmasking.
BasePageHandle* page =
BasePageHandle::FromPayload(const_cast<void*>(value));
HeapHandle& heap_handle = page->heap_handle();
if (V8_LIKELY(!heap_handle.is_incremental_marking_in_progress())) {
#if defined(CPPGC_YOUNG_GENERATION)
if (!heap_handle.is_young_generation_enabled())
return WriteBarrier::Type::kNone;
params.heap = &heap_handle;
params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
params.value_offset = CagedHeapBase::OffsetFromAddress(value);
return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
#else // !CPPGC_YOUNG_GENERATION
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
#endif // !CPPGC_YOUNG_GENERATION
}
// Use marking barrier.
params.heap = &heap_handle;
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
};
template <>
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kNoValuePresent> {
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
if (V8_LIKELY(!WriteBarrier::IsEnabled()))
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
HeapHandle& handle = callback();
#if defined(CPPGC_YOUNG_GENERATION)
if (V8_LIKELY(!handle.is_incremental_marking_in_progress())) {
if (!handle.is_young_generation_enabled()) {
return WriteBarrier::Type::kNone;
}
params.heap = &handle;
// Check if slot is on stack.
if (V8_UNLIKELY(!CagedHeapBase::IsWithinCage(slot))) {
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
}
#else // !defined(CPPGC_YOUNG_GENERATION)
if (V8_UNLIKELY(!handle.is_incremental_marking_in_progress())) {
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
#endif // !defined(CPPGC_YOUNG_GENERATION)
params.heap = &handle;
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
};
#endif // CPPGC_CAGED_HEAP
class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final {
public:
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
}
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, RawPointer value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
return ValueModeDispatch<value_mode>::Get(slot, value.Load(), params,
callback);
}
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
// The slot will never be used in `Get()` below.
return Get<WriteBarrier::ValueMode::kValuePresent>(nullptr, value, params,
callback);
}
private:
template <WriteBarrier::ValueMode value_mode>
struct ValueModeDispatch;
WriteBarrierTypeForNonCagedHeapPolicy() = delete;
};
template <>
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kValuePresent> {
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void*, const void* object,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
// The following check covers nullptr as well as sentinel pointer.
if (object <= static_cast<void*>(kSentinelPointer)) {
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
if (V8_LIKELY(!WriteBarrier::IsEnabled())) {
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
// We know that |object| is within the normal page or in the beginning of a
// large page, so extract the page header by bitmasking.
BasePageHandle* page =
BasePageHandle::FromPayload(const_cast<void*>(object));
HeapHandle& heap_handle = page->heap_handle();
if (V8_LIKELY(heap_handle.is_incremental_marking_in_progress())) {
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
};
template <>
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kNoValuePresent> {
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void*, const void*,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
if (V8_UNLIKELY(WriteBarrier::IsEnabled())) {
HeapHandle& handle = callback();
if (V8_LIKELY(handle.is_incremental_marking_in_progress())) {
params.heap = &handle;
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
}
return WriteBarrier::Type::kNone;
}
};
// static
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
const void* slot, const void* value, WriteBarrier::Params& params) {
return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
params, []() {});
}
// static
template <typename MemberStorage>
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
const void* slot, MemberStorage value, WriteBarrier::Params& params) {
return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
params, []() {});
}
// static
template <typename HeapHandleCallback>
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
const void* slot, WriteBarrier::Params& params,
HeapHandleCallback callback) {
return WriteBarrierTypePolicy::Get<ValueMode::kNoValuePresent>(
slot, nullptr, params, callback);
}
// static
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
const void* value, WriteBarrier::Params& params) {
return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(value, params,
[]() {});
}
// static
void WriteBarrier::DijkstraMarkingBarrier(const Params& params,
const void* object) {
CheckParams(Type::kMarking, params);
#if defined(CPPGC_CAGED_HEAP)
// Caged heap already filters out sentinels.
DijkstraMarkingBarrierSlow(object);
#else // !CPPGC_CAGED_HEAP
DijkstraMarkingBarrierSlowWithSentinelCheck(object);
#endif // !CPPGC_CAGED_HEAP
}
// static
void WriteBarrier::DijkstraMarkingBarrierRange(const Params& params,
const void* first_element,
size_t element_size,
size_t number_of_elements,
TraceCallback trace_callback) {
CheckParams(Type::kMarking, params);
DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size,
number_of_elements, trace_callback);
}
// static
void WriteBarrier::SteeleMarkingBarrier(const Params& params,
const void* object) {
CheckParams(Type::kMarking, params);
#if defined(CPPGC_CAGED_HEAP)
// Caged heap already filters out sentinels.
SteeleMarkingBarrierSlow(object);
#else // !CPPGC_CAGED_HEAP
SteeleMarkingBarrierSlowWithSentinelCheck(object);
#endif // !CPPGC_CAGED_HEAP
}
#if defined(CPPGC_YOUNG_GENERATION)
// static
template <WriteBarrier::GenerationalBarrierType type>
void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) {
CheckParams(Type::kGenerational, params);
const CagedHeapLocalData& local_data = CagedHeapLocalData::Get();
const AgeTable& age_table = local_data.age_table;
// Bail out if the slot (precise or imprecise) is in young generation.
if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung))
return;
// Dispatch between different types of barriers.
// TODO(chromium:1029379): Consider reload local_data in the slow path to
// reduce register pressure.
if constexpr (type == GenerationalBarrierType::kPreciseSlot) {
GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset,
params.heap);
} else if constexpr (type ==
GenerationalBarrierType::kPreciseUncompressedSlot) {
GenerationalBarrierForUncompressedSlotSlow(
local_data, age_table, slot, params.value_offset, params.heap);
} else {
GenerationalBarrierForSourceObjectSlow(local_data, slot, params.heap);
}
}
#endif // !CPPGC_YOUNG_GENERATION
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_

View File

@@ -0,0 +1,78 @@
// Copyright 2020 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 INCLUDE_CPPGC_LIVENESS_BROKER_H_
#define INCLUDE_CPPGC_LIVENESS_BROKER_H_
#include "cppgc/heap.h"
#include "cppgc/member.h"
#include "cppgc/sentinel-pointer.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class LivenessBrokerFactory;
} // namespace internal
/**
* The broker is passed to weak callbacks to allow (temporarily) querying
* the liveness state of an object. References to non-live objects must be
* cleared when `IsHeapObjectAlive()` returns false.
*
* \code
* class GCedWithCustomWeakCallback final
* : public GarbageCollected<GCedWithCustomWeakCallback> {
* public:
* UntracedMember<Bar> bar;
*
* void CustomWeakCallbackMethod(const LivenessBroker& broker) {
* if (!broker.IsHeapObjectAlive(bar))
* bar = nullptr;
* }
*
* void Trace(cppgc::Visitor* visitor) const {
* visitor->RegisterWeakCallbackMethod<
* GCedWithCustomWeakCallback,
* &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this);
* }
* };
* \endcode
*/
class V8_EXPORT LivenessBroker final {
public:
template <typename T>
bool IsHeapObjectAlive(const T* object) const {
// - nullptr objects are considered alive to allow weakness to be used from
// stack while running into a conservative GC. Treating nullptr as dead
// would mean that e.g. custom collections could not be strongified on
// stack.
// - Sentinel pointers are also preserved in weakness and not cleared.
return !object || object == kSentinelPointer ||
IsHeapObjectAliveImpl(
TraceTrait<T>::GetTraceDescriptor(object).base_object_payload);
}
template <typename T>
bool IsHeapObjectAlive(const WeakMember<T>& weak_member) const {
return IsHeapObjectAlive<T>(weak_member.Get());
}
template <typename T>
bool IsHeapObjectAlive(const UntracedMember<T>& untraced_member) const {
return IsHeapObjectAlive<T>(untraced_member.Get());
}
private:
LivenessBroker() = default;
bool IsHeapObjectAliveImpl(const void*) const;
friend class internal::LivenessBrokerFactory;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_

View File

@@ -0,0 +1,35 @@
// Copyright 2020 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 INCLUDE_CPPGC_MACROS_H_
#define INCLUDE_CPPGC_MACROS_H_
#include <cstddef>
#include "cppgc/internal/compiler-specific.h"
namespace cppgc {
// Use CPPGC_STACK_ALLOCATED if the object is only stack allocated.
// Add the CPPGC_STACK_ALLOCATED_IGNORE annotation on a case-by-case basis when
// enforcement of CPPGC_STACK_ALLOCATED should be suppressed.
#if defined(__clang__)
#define CPPGC_STACK_ALLOCATED() \
public: \
using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \
\
private: \
void* operator new(size_t) = delete; \
void* operator new(size_t, void*) = delete; \
static_assert(true, "Force semicolon.")
#define CPPGC_STACK_ALLOCATED_IGNORE(bug_or_reason) \
__attribute__((annotate("stack_allocated_ignore")))
#else // !defined(__clang__)
#define CPPGC_STACK_ALLOCATED() static_assert(true, "Force semicolon.")
#define CPPGC_STACK_ALLOCATED_IGNORE(bug_or_reason)
#endif // !defined(__clang__)
} // namespace cppgc
#endif // INCLUDE_CPPGC_MACROS_H_

View File

@@ -0,0 +1,604 @@
// Copyright 2020 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 INCLUDE_CPPGC_MEMBER_H_
#define INCLUDE_CPPGC_MEMBER_H_
#include <atomic>
#include <cstddef>
#include <type_traits>
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/member-storage.h"
#include "cppgc/internal/pointer-policies.h"
#include "cppgc/sentinel-pointer.h"
#include "cppgc/type-traits.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace subtle {
class HeapConsistency;
} // namespace subtle
class Visitor;
namespace internal {
// MemberBase always refers to the object as const object and defers to
// BasicMember on casting to the right type as needed.
template <typename StorageType>
class V8_TRIVIAL_ABI MemberBase {
public:
using RawStorage = StorageType;
protected:
struct AtomicInitializerTag {};
V8_INLINE MemberBase() = default;
V8_INLINE explicit MemberBase(const void* value) : raw_(value) {}
V8_INLINE MemberBase(const void* value, AtomicInitializerTag) {
SetRawAtomic(value);
}
V8_INLINE explicit MemberBase(RawStorage raw) : raw_(raw) {}
V8_INLINE explicit MemberBase(std::nullptr_t) : raw_(nullptr) {}
V8_INLINE explicit MemberBase(SentinelPointer s) : raw_(s) {}
V8_INLINE const void** GetRawSlot() const {
return reinterpret_cast<const void**>(const_cast<MemberBase*>(this));
}
V8_INLINE const void* GetRaw() const { return raw_.Load(); }
V8_INLINE void SetRaw(void* value) { raw_.Store(value); }
V8_INLINE const void* GetRawAtomic() const { return raw_.LoadAtomic(); }
V8_INLINE void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); }
V8_INLINE RawStorage GetRawStorage() const { return raw_; }
V8_INLINE void SetRawStorageAtomic(RawStorage other) {
reinterpret_cast<std::atomic<RawStorage>&>(raw_).store(
other, std::memory_order_relaxed);
}
V8_INLINE bool IsCleared() const { return raw_.IsCleared(); }
V8_INLINE void ClearFromGC() const { raw_.Clear(); }
private:
friend class MemberDebugHelper;
mutable RawStorage raw_;
};
// The basic class from which all Member classes are 'generated'.
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
class V8_TRIVIAL_ABI BasicMember final : private MemberBase<StorageType>,
private CheckingPolicy {
using Base = MemberBase<StorageType>;
public:
using PointeeType = T;
using RawStorage = typename Base::RawStorage;
V8_INLINE constexpr BasicMember() = default;
V8_INLINE constexpr BasicMember(std::nullptr_t) {} // NOLINT
V8_INLINE BasicMember(SentinelPointer s) : Base(s) {} // NOLINT
V8_INLINE BasicMember(T* raw) : Base(raw) { // NOLINT
InitializingWriteBarrier(raw);
this->CheckPointer(Get());
}
V8_INLINE BasicMember(T& raw) // NOLINT
: BasicMember(&raw) {}
// Atomic ctor. Using the AtomicInitializerTag forces BasicMember to
// initialize using atomic assignments. This is required for preventing
// data races with concurrent marking.
using AtomicInitializerTag = typename Base::AtomicInitializerTag;
V8_INLINE BasicMember(std::nullptr_t, AtomicInitializerTag atomic)
: Base(nullptr, atomic) {}
V8_INLINE BasicMember(SentinelPointer s, AtomicInitializerTag atomic)
: Base(s, atomic) {}
V8_INLINE BasicMember(T* raw, AtomicInitializerTag atomic)
: Base(raw, atomic) {
InitializingWriteBarrier(raw);
this->CheckPointer(Get());
}
V8_INLINE BasicMember(T& raw, AtomicInitializerTag atomic)
: BasicMember(&raw, atomic) {}
// Copy ctor.
V8_INLINE BasicMember(const BasicMember& other)
: BasicMember(other.GetRawStorage()) {}
// Heterogeneous copy constructors. When the source pointer have a different
// type, perform a compress-decompress round, because the source pointer may
// need to be adjusted.
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr>
V8_INLINE BasicMember( // NOLINT
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy, StorageType>& other)
: BasicMember(other.GetRawStorage()) {}
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr>
V8_INLINE BasicMember( // NOLINT
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy, StorageType>& other)
: BasicMember(other.Get()) {}
// Move ctor.
V8_INLINE BasicMember(BasicMember&& other) noexcept
: BasicMember(other.GetRawStorage()) {
other.Clear();
}
// Heterogeneous move constructors. When the source pointer have a different
// type, perform a compress-decompress round, because the source pointer may
// need to be adjusted.
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr>
V8_INLINE BasicMember(
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy,
StorageType>&& other) noexcept
: BasicMember(other.GetRawStorage()) {
other.Clear();
}
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr>
V8_INLINE BasicMember(
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy,
StorageType>&& other) noexcept
: BasicMember(other.Get()) {
other.Clear();
}
// Construction from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
V8_INLINE BasicMember(const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy,
PersistentCheckingPolicy>& p)
: BasicMember(p.Get()) {}
// Copy assignment.
V8_INLINE BasicMember& operator=(const BasicMember& other) {
return operator=(other.GetRawStorage());
}
// Heterogeneous copy assignment. When the source pointer have a different
// type, perform a compress-decompress round, because the source pointer may
// need to be adjusted.
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy>
V8_INLINE BasicMember& operator=(
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy, StorageType>& other) {
if constexpr (internal::IsDecayedSameV<T, U>) {
return operator=(other.GetRawStorage());
} else {
static_assert(internal::IsStrictlyBaseOfV<T, U>);
return operator=(other.Get());
}
}
// Move assignment.
V8_INLINE BasicMember& operator=(BasicMember&& other) noexcept {
operator=(other.GetRawStorage());
other.Clear();
return *this;
}
// Heterogeneous move assignment. When the source pointer have a different
// type, perform a compress-decompress round, because the source pointer may
// need to be adjusted.
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy>
V8_INLINE BasicMember& operator=(
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy,
StorageType>&& other) noexcept {
if constexpr (internal::IsDecayedSameV<T, U>) {
operator=(other.GetRawStorage());
} else {
static_assert(internal::IsStrictlyBaseOfV<T, U>);
operator=(other.Get());
}
other.Clear();
return *this;
}
// Assignment from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
V8_INLINE BasicMember& operator=(
const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy, PersistentCheckingPolicy>&
other) {
return operator=(other.Get());
}
V8_INLINE BasicMember& operator=(T* other) {
Base::SetRawAtomic(other);
AssigningWriteBarrier(other);
this->CheckPointer(Get());
return *this;
}
V8_INLINE BasicMember& operator=(std::nullptr_t) {
Clear();
return *this;
}
V8_INLINE BasicMember& operator=(SentinelPointer s) {
Base::SetRawAtomic(s);
return *this;
}
template <typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy>
V8_INLINE void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy, StorageType>& other) {
auto tmp = GetRawStorage();
*this = other;
other = tmp;
}
V8_INLINE explicit operator bool() const { return !Base::IsCleared(); }
V8_INLINE operator T*() const { return Get(); }
V8_INLINE T* operator->() const { return Get(); }
V8_INLINE T& operator*() const { return *Get(); }
// CFI cast exemption to allow passing SentinelPointer through T* and support
// heterogeneous assignments between different Member and Persistent handles
// based on their actual types.
V8_INLINE V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
// Executed by the mutator, hence non atomic load.
//
// The const_cast below removes the constness from MemberBase storage. The
// following static_cast re-adds any constness if specified through the
// user-visible template parameter T.
return static_cast<T*>(const_cast<void*>(Base::GetRaw()));
}
V8_INLINE void Clear() {
Base::SetRawStorageAtomic(RawStorage{});
}
V8_INLINE T* Release() {
T* result = Get();
Clear();
return result;
}
V8_INLINE const T** GetSlotForTesting() const {
return reinterpret_cast<const T**>(Base::GetRawSlot());
}
V8_INLINE RawStorage GetRawStorage() const {
return Base::GetRawStorage();
}
private:
V8_INLINE explicit BasicMember(RawStorage raw) : Base(raw) {
InitializingWriteBarrier(Get());
this->CheckPointer(Get());
}
V8_INLINE BasicMember& operator=(RawStorage other) {
Base::SetRawStorageAtomic(other);
AssigningWriteBarrier();
this->CheckPointer(Get());
return *this;
}
V8_INLINE const T* GetRawAtomic() const {
return static_cast<const T*>(Base::GetRawAtomic());
}
V8_INLINE void InitializingWriteBarrier(T* value) const {
WriteBarrierPolicy::InitializingBarrier(Base::GetRawSlot(), value);
}
V8_INLINE void AssigningWriteBarrier(T* value) const {
WriteBarrierPolicy::template AssigningBarrier<
StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), value);
}
V8_INLINE void AssigningWriteBarrier() const {
WriteBarrierPolicy::template AssigningBarrier<
StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(),
Base::GetRawStorage());
}
V8_INLINE void ClearFromGC() const { Base::ClearFromGC(); }
V8_INLINE T* GetFromGC() const { return Get(); }
friend class cppgc::subtle::HeapConsistency;
friend class cppgc::Visitor;
template <typename U>
friend struct cppgc::TraceTrait;
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename StorageType1>
friend class BasicMember;
};
// Member equality operators.
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2,
typename StorageType>
V8_INLINE bool operator==(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
StorageType>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
StorageType>& member2) {
if constexpr (internal::IsDecayedSameV<T1, T2>) {
// Check compressed pointers if types are the same.
return member1.GetRawStorage() == member2.GetRawStorage();
} else {
static_assert(internal::IsStrictlyBaseOfV<T1, T2> ||
internal::IsStrictlyBaseOfV<T2, T1>);
// Otherwise, check decompressed pointers.
return member1.Get() == member2.Get();
}
}
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2,
typename StorageType>
V8_INLINE bool operator!=(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
StorageType>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
StorageType>& member2) {
return !(member1 == member2);
}
// Equality with raw pointers.
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType, typename U>
V8_INLINE bool operator==(
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
StorageType>& member,
U* raw) {
// Never allow comparison with erased pointers.
static_assert(!internal::IsDecayedSameV<void, U>);
if constexpr (internal::IsDecayedSameV<T, U>) {
// Check compressed pointers if types are the same.
return member.GetRawStorage() == StorageType(raw);
} else if constexpr (internal::IsStrictlyBaseOfV<T, U>) {
// Cast the raw pointer to T, which may adjust the pointer.
return member.GetRawStorage() == StorageType(static_cast<T*>(raw));
} else {
// Otherwise, decompressed the member.
return member.Get() == raw;
}
}
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType, typename U>
V8_INLINE bool operator!=(
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
StorageType>& member,
U* raw) {
return !(member == raw);
}
template <typename T, typename U, typename WeaknessTag,
typename WriteBarrierPolicy, typename CheckingPolicy,
typename StorageType>
V8_INLINE bool operator==(
T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>& member) {
return member == raw;
}
template <typename T, typename U, typename WeaknessTag,
typename WriteBarrierPolicy, typename CheckingPolicy,
typename StorageType>
V8_INLINE bool operator!=(
T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>& member) {
return !(raw == member);
}
// Equality with sentinel.
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator==(
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
StorageType>& member,
SentinelPointer) {
return member.GetRawStorage().IsSentinel();
}
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator!=(
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
StorageType>& member,
SentinelPointer s) {
return !(member == s);
}
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator==(
SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>& member) {
return member == s;
}
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator!=(
SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>& member) {
return !(s == member);
}
// Equality with nullptr.
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator==(
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
StorageType>& member,
std::nullptr_t) {
return !static_cast<bool>(member);
}
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator!=(
const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy,
StorageType>& member,
std::nullptr_t n) {
return !(member == n);
}
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator==(
std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>& member) {
return member == n;
}
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy, typename StorageType>
V8_INLINE bool operator!=(
std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>& member) {
return !(n == member);
}
// Relational operators.
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2,
typename StorageType>
V8_INLINE bool operator<(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
StorageType>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
StorageType>& member2) {
static_assert(
internal::IsDecayedSameV<T1, T2>,
"Comparison works only for same pointer type modulo cv-qualifiers");
return member1.GetRawStorage() < member2.GetRawStorage();
}
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2,
typename StorageType>
V8_INLINE bool operator<=(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
StorageType>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
StorageType>& member2) {
static_assert(
internal::IsDecayedSameV<T1, T2>,
"Comparison works only for same pointer type modulo cv-qualifiers");
return member1.GetRawStorage() <= member2.GetRawStorage();
}
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2,
typename StorageType>
V8_INLINE bool operator>(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
StorageType>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
StorageType>& member2) {
static_assert(
internal::IsDecayedSameV<T1, T2>,
"Comparison works only for same pointer type modulo cv-qualifiers");
return member1.GetRawStorage() > member2.GetRawStorage();
}
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2,
typename StorageType>
V8_INLINE bool operator>=(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1,
StorageType>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2,
StorageType>& member2) {
static_assert(
internal::IsDecayedSameV<T1, T2>,
"Comparison works only for same pointer type modulo cv-qualifiers");
return member1.GetRawStorage() >= member2.GetRawStorage();
}
template <typename T, typename WriteBarrierPolicy, typename CheckingPolicy,
typename StorageType>
struct IsWeak<internal::BasicMember<T, WeakMemberTag, WriteBarrierPolicy,
CheckingPolicy, StorageType>>
: std::true_type {};
} // namespace internal
/**
* Members are used in classes to contain strong pointers to other garbage
* collected objects. All Member fields of a class must be traced in the class'
* trace method.
*/
template <typename T>
using Member = internal::BasicMember<
T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy,
internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>;
/**
* WeakMember is similar to Member in that it is used to point to other garbage
* collected objects. However instead of creating a strong pointer to the
* object, the WeakMember creates a weak pointer, which does not keep the
* pointee alive. Hence if all pointers to to a heap allocated object are weak
* the object will be garbage collected. At the time of GC the weak pointers
* will automatically be set to null.
*/
template <typename T>
using WeakMember = internal::BasicMember<
T, internal::WeakMemberTag, internal::DijkstraWriteBarrierPolicy,
internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>;
/**
* UntracedMember is a pointer to an on-heap object that is not traced for some
* reason. Do not use this unless you know what you are doing. Keeping raw
* pointers to on-heap objects is prohibited unless used from stack. Pointee
* must be kept alive through other means.
*/
template <typename T>
using UntracedMember = internal::BasicMember<
T, internal::UntracedMemberTag, internal::NoWriteBarrierPolicy,
internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>;
namespace subtle {
/**
* UncompressedMember. Use with care in hot paths that would otherwise cause
* many decompression cycles.
*/
template <typename T>
using UncompressedMember = internal::BasicMember<
T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy,
internal::DefaultMemberCheckingPolicy, internal::RawPointer>;
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_MEMBER_H_

View File

@@ -0,0 +1,65 @@
// Copyright 2020 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 INCLUDE_CPPGC_NAME_PROVIDER_H_
#define INCLUDE_CPPGC_NAME_PROVIDER_H_
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* NameProvider allows for providing a human-readable name for garbage-collected
* objects.
*
* There's two cases of names to distinguish:
* a. Explicitly specified names via using NameProvider. Such names are always
* preserved in the system.
* b. Internal names that Oilpan infers from a C++ type on the class hierarchy
* of the object. This is not necessarily the type of the actually
* instantiated object.
*
* Depending on the build configuration, Oilpan may hide names, i.e., represent
* them with kHiddenName, of case b. to avoid exposing internal details.
*/
class V8_EXPORT NameProvider {
public:
/**
* Name that is used when hiding internals.
*/
static constexpr const char kHiddenName[] = "InternalNode";
/**
* Name that is used in case compiler support is missing for composing a name
* from C++ types.
*/
static constexpr const char kNoNameDeducible[] = "<No name>";
/**
* Indicating whether the build supports extracting C++ names as object names.
*
* @returns true if C++ names should be hidden and represented by kHiddenName.
*/
static constexpr bool SupportsCppClassNamesAsObjectNames() {
#if CPPGC_SUPPORTS_OBJECT_NAMES
return true;
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
return false;
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
}
virtual ~NameProvider() = default;
/**
* Specifies a name for the garbage-collected object. Such names will never
* be hidden, as they are explicitly specified by the user of this API.
*
* @returns a human readable name for the object.
*/
virtual const char* GetHumanReadableName() const = 0;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_NAME_PROVIDER_H_

Some files were not shown because too many files have changed in this diff Show More