profile
viewpoint
Ingvar Stepanyan RReverser Google London, UK https://rreverser.com/ Obsessed D2D (tools & specs) programmer, speaker and performance engineer.

emscripten-core/emscripten 18641

Emscripten: An LLVM-to-Web Compiler

acornjs/acorn 5676

A small, fast, JavaScript-based JavaScript parser

fkling/astexplorer 2892

A web tool to explore the ASTs generated by various parsers.

inikulin/parse5 2307

HTML parsing/serialization toolset for Node.js. WHATWG HTML Living Standard (aka HTML5)-compliant.

facebook/jsx 1423

The JSX specification is a XML-like syntax extension to ECMAScript.

acornjs/acorn-jsx 421

Alternative, faster React.js JSX parser

binast/binjs-ref 375

Reference implementation for the JavaScript Binary AST format

dherman/esprit 265

A JavaScript parser written in Rust

cloudflare/serde-wasm-bindgen 120

Native integration of Serde with wasm-bindgen

mourner/delaunator-rs 70

Fast 2D Delaunay triangulation in Rust. A port of Delaunator.

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),

Hmm yeah I suppose that's another option. I probably won't be able to return to this PR until ~Tuesday, but will update correspondingly as soon as possible.

RReverser

comment created time in 15 hours

issue commentacornjs/acorn-jsx

how is this parser work? I couldn't parse it.

Please provide more details:

  1. What did you try to do?
  2. What you expected to happen?
  3. What happened instead?

From here it looks like you're trying to use parsing result (AST) as a React component, which doesn't make much sense...

Taymindis

comment created time in 19 hours

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),

but I don't understand enough about what symbols you are planning to add that would need that. None of the symbols added in this PR need it do they? What symbols are there besides code and data?

I've mentioned few above - we might want to distinguish memories from tables from globals in the future, as semantically they're different things (even if these semantics are unique to Wasm symbols and not others).

it's possible you don't need the unified API that this crate provides

I'm aware, and actually already using wasmparser directly for now, but I still think it would be useful to have a unified API for being able to match DWARF information to public symbols via same API across various crates. And, even if I end up keeping separate handlers for Wasm and other formats, such addition might be useful for other consumers of the object crate too, hence the upstreaming.

RReverser

comment created time in 19 hours

pull request commentestree/estree

Update es2020.md for Dec 2019

Sorry, it's really hard to follow the discussion at this point and understand the proposed changes and whether the parties have agreed. If there is a chance of splitting some non-controversial part off as noted above, that would be awesome.

mysticatea

comment created time in a day

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),

It still feels weird that imports get an "undefined" section instead of either the section in which they're defined or the section they are pointing to (like exports)... but I guess okay, I can change the PR, as for now the goal is just to match the unified API rather than provide all possible details.

I do wonder though how we're going to extend them if/when in future we want to collect and distinguish e.g. imported, local and exported globals, tables and memories. I guess we'll need to introduce new symbol kinds, if using SymbolSection for imports is not an option?

RReverser

comment created time in a day

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),

That model mostly seems reasonable. But one question: how would non-function imports look like? E.g. how would you distinguish a memory import from a function one?

Overall agreed regarding redundancy of SymbolSection+SymbolKind, but in this case it seems that only SymbolKind would currently help?

If so, I'd be open to merging them in a single enum if you are open to changing API that way.

RReverser

comment created time in 2 days

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),+                            weak: false,+                            scope: SymbolScope::Dynamic,+                            flags: SymbolFlags::None,+                        });+                    }+                }+                wp::SectionCode::Function => {+                    local_func_kinds = vec![+                        LocalFunctionKind::Unknown;+                        section+                            .get_function_section_reader()+                            .map_err(|_| "Couldn't read header of the function section")?+                            .get_count() as usize+                    ];+                }+                wp::SectionCode::Export => {+                    if let Some(main_file_symbol) = main_file_symbol.take() {+                        file.symbols.push(main_file_symbol);+                    }++                    for export in section+                        .get_export_section_reader()+                        .map_err(|_| "Couldn't read header of the export section")?+                    {+                        let export = export.map_err(|_| "Couldn't read an export item")?;++                        file.symbols.push(Symbol {+                            name: Some(export.field),+                            address: 0,+                            size: 0,+                            kind: match export.kind {+                                wp::ExternalKind::Function => {+                                    if let Some(local_func_id) =+                                        export.index.checked_sub(imported_funcs_count)+                                    {+                                        let local_func_kind =+                                            &mut local_func_kinds[local_func_id as usize];+                                        if let LocalFunctionKind::Unknown = local_func_kind {+                                            *local_func_kind = LocalFunctionKind::Exported {+                                                symbol_ids: Vec::new(),+                                            };+                                        }+                                        let symbol_ids = match local_func_kind {+                                            LocalFunctionKind::Exported { symbol_ids } => {+                                                symbol_ids+                                            }+                                            _ => unreachable!(),+                                        };+                                        symbol_ids.push(file.symbols.len() as u32);+                                    }+                                    SymbolKind::Text+                                }+                                wp::ExternalKind::Table+                                | wp::ExternalKind::Memory+                                | wp::ExternalKind::Global => SymbolKind::Data,+                            },+                            section: SymbolSection::Section(SectionIndex(SECTION_EXPORT)),+                            weak: false,+                            scope: SymbolScope::Dynamic,+                            flags: SymbolFlags::None,+                        });+                    }+                }+                wp::SectionCode::Start => {+                    entry_func_id = Some(+                        section+                            .get_start_section_content()+                            .map_err(|_| "Couldn't read contents of the start section")?,+                    );+                }+                wp::SectionCode::Code => {+                    if let Some(main_file_symbol) = main_file_symbol.take() {+                        file.symbols.push(main_file_symbol);+                    }++                    for (i, (body, local_func_kind)) in section+                        .get_code_section_reader()+                        .map_err(|_| "Couldn't read header of the code section")?+                        .into_iter()+                        .zip(&mut local_func_kinds)+                        .enumerate()+                    {+                        let body = body.map_err(|_| "Couldn't read a function body")?;+                        let range = body.range();++                        let section = SymbolSection::Section(SectionIndex(SECTION_CODE));+                        let address = range.start as u64;

Huh, good catch! I can swear it used to be relative to a code section, but either I changed a code or maybe that was a bug in some older version of wasmparser :/

I'll update the PR to use section-relative addresses later.

RReverser

comment created time in 2 days

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),

Hmm it feels like duplication then.

In this implementation kind field clearly describes whether the symbol points to a function, data, or something else, whereas section describes where the symbol itself is placed.

If I change section to point to code section, data, etc., then I only get duplication, and it becomes harder to distinguish imported symbols from e.g. exported ones, because both now would have SymbolScope::Dynamic, SymbolKind::Text and SymbolSection::Section(SectionIndex(SECTION_CODE)).

We still need to somehow preserve the information about the section in which symbol itself is defined, and for that section field seems like the most appropriate place...

RReverser

comment created time in 2 days

CommitCommentEvent

create barnchRReverser/wasm-bindgen

branch : issue-demo

created branch time in 2 days

push eventRReverser/wasm-bindgen

Ingvar Stepanyan

commit sha d26068dc6ccfc07d0ab1cd2ead85193ddc3880cd

Propagate missing memory argument (#2011) Fixes #2010.

view details

Ingvar Stepanyan

commit sha aabfdbf25d1bdbd7417dbdcd54ee6cc297824ff7

Create new WorkerPool each time Demonstrates a memory corruption issue.

view details

push time in 2 days

issue openedrustwasm/wasm-pack

--profiling doesn't preserve function names

🐛 Bug description

profiling mode is essentially equivalent to release and doesn't preserve debug info as documented (not even function names necessary for profiling or basic debugging).

🤔 Expected Behavior

The generated .wasm contains a custom "names" section that is subsequently used by engines for function names in error stacks and profiling traces.

👟 Steps to reproduce

Compile any package with wasm-pack --profiling.

Run an example app in a browser profiler or a debugger and observe that all functions are shown as just wasm-function[...], just like in a release mode.

Alternatively, check the generated .wasm with wasm-objdump -h for presence of "names" section (it's absent).

🌍 Your environment

Include the relevant details of your environment. wasm-pack version: 0.9.1 rustc version: 1.41.0


Extra info

This seems to be caused by wasm-pack running wasm-opt without a -g flag, which is necessary to preserve function names information.

created time in 2 days

startedwoltapp/blurhash

started time in 2 days

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),+                            weak: false,+                            scope: SymbolScope::Dynamic,+                            flags: SymbolFlags::None,+                        });+                    }+                }+                wp::SectionCode::Function => {+                    local_func_kinds = vec![+                        LocalFunctionKind::Unknown;+                        section+                            .get_function_section_reader()+                            .map_err(|_| "Couldn't read header of the function section")?+                            .get_count() as usize+                    ];+                }+                wp::SectionCode::Export => {+                    if let Some(main_file_symbol) = main_file_symbol.take() {+                        file.symbols.push(main_file_symbol);+                    }++                    for export in section+                        .get_export_section_reader()+                        .map_err(|_| "Couldn't read header of the export section")?+                    {+                        let export = export.map_err(|_| "Couldn't read an export item")?;++                        file.symbols.push(Symbol {+                            name: Some(export.field),+                            address: 0,+                            size: 0,+                            kind: match export.kind {+                                wp::ExternalKind::Function => {+                                    if let Some(local_func_id) =+                                        export.index.checked_sub(imported_funcs_count)+                                    {+                                        let local_func_kind =+                                            &mut local_func_kinds[local_func_id as usize];+                                        if let LocalFunctionKind::Unknown = local_func_kind {+                                            *local_func_kind = LocalFunctionKind::Exported {+                                                symbol_ids: Vec::new(),+                                            };+                                        }+                                        let symbol_ids = match local_func_kind {+                                            LocalFunctionKind::Exported { symbol_ids } => {+                                                symbol_ids+                                            }+                                            _ => unreachable!(),+                                        };+                                        symbol_ids.push(file.symbols.len() as u32);+                                    }+                                    SymbolKind::Text+                                }+                                wp::ExternalKind::Table+                                | wp::ExternalKind::Memory+                                | wp::ExternalKind::Global => SymbolKind::Data,+                            },+                            section: SymbolSection::Section(SectionIndex(SECTION_EXPORT)),

This is, unfortunately, a bit convoluted due to the nature of streaming parsing, but the idea is that when we read this section, we start with all symbols as just "export" symbols because we don't know yet where in the file they're pointing to.

Later, when we read the "code" section and find out that this export symbol was pointing to a local function, we update its section, kind, address and size to mark it as such (see line 237).

Otherwise, it remains an "export" section symbol.

RReverser

comment created time in 2 days

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),+                            weak: false,+                            scope: SymbolScope::Dynamic,+                            flags: SymbolFlags::None,+                        });+                    }+                }+                wp::SectionCode::Function => {+                    local_func_kinds = vec![+                        LocalFunctionKind::Unknown;+                        section+                            .get_function_section_reader()+                            .map_err(|_| "Couldn't read header of the function section")?+                            .get_count() as usize+                    ];+                }+                wp::SectionCode::Export => {+                    if let Some(main_file_symbol) = main_file_symbol.take() {+                        file.symbols.push(main_file_symbol);+                    }++                    for export in section+                        .get_export_section_reader()+                        .map_err(|_| "Couldn't read header of the export section")?+                    {+                        let export = export.map_err(|_| "Couldn't read an export item")?;++                        file.symbols.push(Symbol {+                            name: Some(export.field),+                            address: 0,+                            size: 0,+                            kind: match export.kind {+                                wp::ExternalKind::Function => {+                                    if let Some(local_func_id) =+                                        export.index.checked_sub(imported_funcs_count)+                                    {+                                        let local_func_kind =+                                            &mut local_func_kinds[local_func_id as usize];+                                        if let LocalFunctionKind::Unknown = local_func_kind {+                                            *local_func_kind = LocalFunctionKind::Exported {+                                                symbol_ids: Vec::new(),+                                            };+                                        }+                                        let symbol_ids = match local_func_kind {+                                            LocalFunctionKind::Exported { symbol_ids } => {+                                                symbol_ids+                                            }+                                            _ => unreachable!(),+                                        };+                                        symbol_ids.push(file.symbols.len() as u32);+                                    }+                                    SymbolKind::Text+                                }+                                wp::ExternalKind::Table+                                | wp::ExternalKind::Memory+                                | wp::ExternalKind::Global => SymbolKind::Data,+                            },+                            section: SymbolSection::Section(SectionIndex(SECTION_EXPORT)),+                            weak: false,+                            scope: SymbolScope::Dynamic,+                            flags: SymbolFlags::None,+                        });+                    }+                }+                wp::SectionCode::Start => {+                    entry_func_id = Some(+                        section+                            .get_start_section_content()+                            .map_err(|_| "Couldn't read contents of the start section")?,+                    );+                }+                wp::SectionCode::Code => {+                    if let Some(main_file_symbol) = main_file_symbol.take() {+                        file.symbols.push(main_file_symbol);+                    }++                    for (i, (body, local_func_kind)) in section+                        .get_code_section_reader()+                        .map_err(|_| "Couldn't read header of the code section")?+                        .into_iter()+                        .zip(&mut local_func_kinds)+                        .enumerate()+                    {+                        let body = body.map_err(|_| "Couldn't read a function body")?;+                        let range = body.range();++                        let section = SymbolSection::Section(SectionIndex(SECTION_CODE));+                        let address = range.start as u64;

No, range.start at this point is relative to the code section (please check the example dumps in the PR).

RReverser

comment created time in 2 days

Pull request review commentgimli-rs/object

Enhance Wasm symbol reading

 impl<'data> WasmFile<'data> {          let mut file = WasmFile::default(); +        let mut main_file_symbol = Some(Symbol {+            name: None,+            address: 0,+            size: 0,+            kind: SymbolKind::File,+            section: SymbolSection::None,+            weak: false,+            scope: SymbolScope::Compilation,+            flags: SymbolFlags::None,+        });++        let mut imported_funcs_count = 0;+        let mut local_func_kinds = Vec::new();+        let mut entry_func_id = None;+         for section in module {-            let section = section.map_err(|_| "Invalid section header")?;+            let section = section.map_err(|_| "Couldn't read section header")?;              match section.code {-                wp::SectionCode::Custom { kind, name } => {-                    if kind == wp::CustomSectionKind::Name {-                        file.names_data = Some(section.range().slice(data));-                    } else if name.starts_with(".debug_") {-                        file.has_debug_symbols = true;+                wp::SectionCode::Import => {+                    let mut last_module_name = None;++                    for import in section+                        .get_import_section_reader()+                        .map_err(|_| "Couldn't read header of the import section")?+                    {+                        let import = import.map_err(|_| "Couldn't read an import item")?;+                        let module_name = Some(import.module);++                        if last_module_name != module_name {+                            file.symbols.push(Symbol {+                                name: module_name,+                                address: 0,+                                size: 0,+                                kind: SymbolKind::File,+                                section: SymbolSection::None,+                                weak: false,+                                scope: SymbolScope::Dynamic,+                                flags: SymbolFlags::None,+                            });+                            last_module_name = module_name;+                        }++                        let kind = match import.ty {+                            wp::ImportSectionEntryType::Function(_) => {+                                imported_funcs_count += 1;+                                SymbolKind::Text+                            }+                            wp::ImportSectionEntryType::Table(_)+                            | wp::ImportSectionEntryType::Memory(_)+                            | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data,+                        };++                        file.symbols.push(Symbol {+                            name: Some(import.field),+                            address: 0,+                            size: 0,+                            kind,+                            section: SymbolSection::Section(SectionIndex(SECTION_IMPORT)),

Why? I know they're for objects on other platforms, but I think it's because other platforms don't encode type of the import, while in Wasm we get more information.

RReverser

comment created time in 2 days

pull request commentv8/v8.dev

Add Intl.DisplayNames feature explainer

LGTM. Let's publish this next Tuesday?

I was initially thinking tomorrow. Do you want to wait for V8 release post first?

syg

comment created time in 3 days

delete branch RReverser/wasm-bindgen

delete branch : fix-2010

delete time in 3 days

create barnchRReverser/wasm-bindgen

branch : fix-2010

created branch time in 3 days

PR opened rustwasm/wasm-bindgen

Propagate missing memory argument

Fixes #2010.

+2 -2

0 comment

1 changed file

pr created time in 3 days

issue commentrustwasm/wasm-bindgen

Regression: can't instantiate wasm-bindgen with instance of WebAssembly.Module

Nothing in that particular PR seems to stand out, so could've been an earlier regression as well.

RReverser

comment created time in 3 days

issue openedrustwasm/wasm-bindgen

Regression: can't instantiate wasm-bindgen with instance of WebAssembly.Module

Describe the Bug

On master wasm-bindgen trying to instantiate wasm-bindgen with a custom instance of WebAssembly.Module (e.g. in a Cloudflare Worker) results in an error due to maybe_memory being undefined:

image

If you check the generated code with ESLint, it also warns that variable is not defined anywhere:

image

This appears to be a regression, perhaps caused by a refactor in #1996? (cc @Pauan)

created time in 3 days

issue openedrustwasm/wasm-pack

Provide a way to detect wasm-pack `target` via `cfg`

💡 Feature description

Currently, there is no way to do perform conditional compilation based on the --target passed to wasm-pack.

It would be great if wasm-pack would pass it on via --cfg to Rust (should be easy enough to pass it in RUSTFLAGS), so that users could check this target in their code as any other conditional compilation attribute.

💻 Basic example

pub const HAS_ESM_SUPPORT: bool = cfg!(any(
  wasm_pack_target = "bundler",
  wasm_pack_target = "web"
));

created time in 3 days

Pull request review commentv8/v8.dev

Add a blog post: Understanding the ECMAScript spec, part 2

+---+title: 'Understanding the ECMAScript spec, part 2'+author: '[Marja Hölttä](https://twitter.com/marjakh), speculative specification spectator'+avatars:+  - marja-holtta+date: 2020-02-11 13:33:37+tags:+  - ECMAScript+description: 'Tutorial on reading the ECMAScript specification'+tweet: ''+---++... where we practice our awesome spec reading skills some more.++## Previous episodes++If you haven't had a look at the previous episodes, now it's a good time to do so!++In [part 1](https://v8.dev/blog/understanding-ecmascript-part-1) we read through a simple method, `Object.prorotype.hasOwnProperty`, and other **abstract operations** it invokes. We familiarized ourselves with the shorhands `?` and `!`related to error handling. We encountered **language types**, **specification types**, **internal slots** and **internal methods**.++## Ready for part 2?++A fun way to get to know the spec is to start with a JavaScript feature we know is there, and find out how it's specified.++We know that properties are looked up in the prototype chain: if an object doesn't have the property we're trying to read, we walk up the prototype chain until we find it (or find an object which no longer has a prototype).++For example:++```javascript+const o1 = {'foo' : 2511};+const o2 = {};+console.log(o2.foo); // undefined+Object.setPrototypeOf(o2, o1);+console.log(o2.foo); // 2511+```++## Where's the prototype walk defined?++Let's try to find out where this behavior is defined. A good place to start is a list of [Object Internal Methods](https://tc39.es/ecma262/#sec-object-internal-methods-and-internal-slots).++There's both `[[GetOwnProperty]]` and `[[Get]]` &mdash; now we're interested in the version that isn't restricted to _own_ properties, so we'll go with `[[Get]]`.++Unfortunately, the [Property Descriptor specification type](https://tc39.es/ecma262/#sec-property-descriptor-specification-type) also has a field called `[[Get]]`, so while browsing the spec for `[[Get]]`, we need to carefully distinguish between the two independent usages.++The internal method `[[Get]]` delegates to `OrdinaryGet`:++> [`[[Get]] ( P, Receiver )`](https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver)+>+> When the `[[Get]]` internal method of `O` is called with property key `P` and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Return `? OrdinaryGet(O, P, Receiver)`.++We'll see shortly that `Receiver` is the value which is used as the **this value** when calling a getter function of an accessor property.++`OrdinaryGet` is defined like this:++> [`OrdinaryGet ( O, P, Receiver )`](https://tc39.es/ecma262/#sec-ordinaryget)+>+> When the abstract operation `OrdinaryGet` is called with Object `O`, property key `P`, and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Assert: `IsPropertyKey(P)` is `true`.+> 2. Let `desc` be `? O.[[GetOwnProperty]](P)`.+> 3. If `desc` is `undefined`, then+> a. Let `parent` be `? O.[[GetPrototypeOf]]()`.+> b. If `parent` is `null`, return `undefined`.+> c. Return `? parent.[[Get]](P, Receiver)`.+> 4. If `IsDataDescriptor(desc)` is `true`, return `desc.[[Value]]`.+> 5. Assert: `IsAccessorDescriptor(desc)` is `true`.+> 6. Let `getter` be `desc.[[Get]]`.+> 7. If `getter` is `undefined`, return `undefined`.+> 8. Return `? Call(getter, Receiver)`.++The prototype chain walk is inside step 3: if we don't find the property as an own property, we recurse into the prototype's `[[Get]]` method.++## What's `Receiver` and where is it coming from?++The `Receiver` parameter is only used in the case of accessor properties in step 8. It's passed as the **this value** when calling the getter function of an accessor property.++`OrdinaryGet` passes the original `Receiver` throughout the recursion, unchanged (step 3 c). Let's find out where the `Receiver` is originally coming from!++Searching for places where `[[Get]]` is called we find an abstract operation `GetValue` which operates on References. Reference is a specification type, consisting of a base value, the reference name and a strict reference flag. In the case of `o2.foo`, the base value is the Object `o2`, the reference name is the String `"foo"` and the strict reference flag is `false`, since the example code is sloppy.++### Side track: References++Side track: A Reference is not a Record, even though it sounds like it could be. It contains three components, which could equally well be expressed as three fixed named values. Here the spec takes a different approach, and defines References as a higher-level data type. This is because of historical reasons.++### Back to `GetValue`++Let's look at how `GetValue` is defined:++> [`GetValue ( V )`](https://tc39.es/ecma262/#sec-getvalue)+>+> 1. `ReturnIfAbrupt(V)`.+> 2. If `Type(V)` is not `Reference`, return `V`.+> 3. Let `base` be `GetBase(V)`.+> 4. If `IsUnresolvableReference(V)` is `true`, throw a `ReferenceError` exception.+> 5. If `IsPropertyReference(V)` is `true`, then+> a. If `HasPrimitiveBase(V)` is `true`, then+> i. Assert: In this case, `base` will never be `undefined` or `null`.+> ii. Set `base` to `! ToObject(base)`.+> b. Return `? base.[[Get]](GetReferencedName(V), GetThisValue(V))`.+> 6. Else,+> a. Assert: `base` is an Environment Record.+> b. Return `? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))`++The reference in our example is `o2.foo` which is a property reference. So we take branch 5. We don't take the branch in 5 a, since the base (`o2`) is not a primitive value (a Boolean, String, Symbol, BigInt or Number).++Then we call `[[Get]]` in step 5 b. The `Receiver` we pass is `GetThisValue(V)`. In this case, it's just the basevalue of the Reference:++> [`GetThisValue( V )`](https://tc39.es/ecma262/#sec-getthisvalue)+>+> 1. Assert: `IsPropertyReference(V)` is `true`.+> 2. If `IsSuperReference(V)` is `true`, then+> a. Return the value of the `thisValue` component of the reference `V`.+> 3. Return `GetBase(V)`.++For `o2.foo`, we don't take the branch in step 2, since it's not a super reference (such as `super.foo`), but we take step 3 and return the base value of the reference which is `o2`.++Piecing everything together, we find out that we set the `Receiver` to be the base of the original reference, and then we keep it unchanged during the prototype chain walk. Finally, if the property we find is an accessor property, we use the `Receiver` as the **this value** when calling it.++In particular, the **this value** inside a getter refers to the original object where we tried to get the property from, not the one where we found the property during the prototype chain walk.++Let's try it out!++```javascript+const o1 = { x: 10, get foo() { return this.x; } };+let o2 = {};+Object.setPrototypeOf(o2, o1);+o2.x = 50;+o2.foo; // will return 50+```++In this example, we have an accessor property called `foo` and we define a getter for it. The getter returns `this.x`.++Then we access `o2.foo` - what does the getter return?++We found out that when we call the getter, the **this value** is the object where we originally tried to get the property from, not the object where we found it. In this case the **this value** is `o2`, not `o1`. We can verify that by checking whether the getter returns `o2.x` or `o1.x`, and indeed, it returns `o2.x`.++(Note that setting `o2.x = 50` adds a property called `x` in `o2` and doesn't overwrite the property `x` in `o1`.)++It works! We were able to predict the behavior of this code snippet based on what we read in the spec.++## Accessing properties - why does it invoke `[[Get]]`?++But where does the spec say that the Object internal method `[[Get]]` will get invoked when accessing a property like `o2.foo`? Surely that has to be defined somewhere. Don't take my word for it!++We found out that the Object internal method `[[Get]]` is called from the abstract operation `GetValue` which operates on References. But where is `GetValue` called from?++### Runtime Semantics++The grammar rules of the spec define the syntax of the language. [Runtime semantics](https://tc39.es/ecma262/#sec-runtime-semantics) define what the syntactic constructs "mean" (how to evaluate them at runtime).++We'll take a deeper look into the grammar rules in a later episode, let's keep it simple for now! In particular, we can ignore the subscripts (`Yield`, `Await` and so on) in the productions for this episode.++(If you're not familiar with [context-free grammars](https://en.wikipedia.org/wiki/Context-free_grammar), it's a good idea to have a look now!)++The following productions describe how a `MemberExpression` looks like:++> [`MemberExpression :`](https://tc39.es/ecma262/#prod-MemberExpression)+>+> `PrimaryExpression`+> `MemberExpression [ Expression ]`+> `MemberExpression . IdentifierName`+> `MemberExpression TemplateLiteral`+> `SuperProperty`+> `MetaProperty`+> `new MemberExpression Arguments`++Here we have 8 productions for `MemberExpression`. A `MemberExpression` can be just a `PrimaryExpression`. Alternatively, a `MemberExpression` can be constructed from another `MemberExpression` and `Expression` by piecing them together: `MemberExpression [ Expression ]`, for example `o2['foo']`. Or it can be `MemberExpression . IdentifierName`, for example `o2.foo` &mdash; this is the production relevant for our example.++Runtime semantics for the production `MemberExpression : MemberExpression . IdentifierName` define the set of steps to take when evaluating it:++> [Runtime Semantics: Evaluation for `MemberExpression : MemberExpression . IdentifierName`](https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation)+>+> 1. Let `baseReference` be the result of evaluating `MemberExpression`.+> 2. Let `baseValue` be `? GetValue(baseReference)`.+> 3. If the code matched by this `MemberExpression` is strict mode code, let `strict` be `true`; else let `strict` be `false`.+> 4. Return `? EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict)`.++The algorithm delegates to the abstract operation `EvaluatePropertyAccessWithIdentifierKey`, so we need to read it too:++> [`EvaluatePropertyAccessWithIdentifierKey( baseValue, identifierName, strict )`](https://tc39.es/ecma262/#sec-evaluate-property-access-with-identifier-key)+>+> The abstract operation `EvaluatePropertyAccessWithIdentifierKey` takes as arguments a value `baseValue`, a Parse Node `identifierName`, and a Boolean argument `strict`. It performs the following steps:+>+> 1. Assert: `identifierName` is an `IdentifierName`+> 2. Let `bv` be `? RequireObjectCoercible(baseValue)`.+> 3. Let `propertyNameString` be `StringValue` of `identifierName`.+> 4. Return a value of type Reference whose base value component is `bv`, whose referenced name component is `propertyNameString`, and whose strict reference flag is `strict`.++That is: `EvaluatePropertyAccessWithIdentifierKey` constructs a Reference which uses the provided `baseValue` as the base, the string value of `identifierName` as the property name, and `strict` as the strict mode flag.++Eventually this Reference gets passed to `GetValue`. This is defined in several places in the spec, depending on how the Reference ends up being used.++### Property access as a parameter++For example, we can use the property access as a parameter.++```javascript+console.log(o2.foo);+```++In this case, the behavior is defined in the runtime semantics of `ArgumentList` production which calls `GetValue` on the argument:++> [Runtime Semantics: ArgumentListEvaluation](https://tc39.es/ecma262/#sec-argument-lists-runtime-semantics-argumentlistevaluation)+>+> `ArgumentList : AssignmentExpression`+>+> 1. Let `ref` be the result of evaluating `AssignmentExpression`.+> 2. Let `arg` be `? GetValue(ref)`.+> 3. Return a List whose sole item is `arg`.++`o2.foo` doesn't look like an `AssignmentExpression` but it is one, so this production is applicable. (Why `o2.foo` is an `AssignmentExpression` will be explained later in this post.)++So, the `AssignmentExpression` is `o2.foo`. `ref`, the result of evaluating `o2.foo`, is the above mentioned Reference. Now we call `GetValue` on it.++### Property access as the right hand side of an assignment++We can also use the property access as a right hand side of an assignment:++```javascript+x = o2.foo;+```++In this case, the behavior is defined in the runtime semantics for the `AssignmentExpression : LeftHandSide = AssignmentExpression` production. Also this ends up calling `GetValue` on the result of evaluating the right hand side `AssignmentExpression`.++> [Runtime Semantics: Evaluation for `AssignmentExpression : LeftHandSideExpression = AssignmentExpression`](https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation)+>+> 1. If `LeftHandSideExpression` is neither an `ObjectLiteral` nor an `ArrayLiteral`, then+>     1. Let `lref` be the result of evaluating `LeftHandSideExpression`.+>     1. `ReturnIfAbrupt(lref)`.+>     1. If `IsAnonymousFunctionDefinition(AssignmentExpression)` and `IsIdentifierRef` of `LeftHandSideExpression` are both `true`, then+>         1. Let `rval` be `NamedEvaluation` of `AssignmentExpression` with argument `GetReferencedName(lref)`.+>     1. Else,+>         1. Let `rref` be the result of evaluating `AssignmentExpression`.+>         1. Let `rval` be `? GetValue(rref)`.+>     1. Perform `? PutValue(lref, rval)`.+>     1. Return `rval`.+> 1. Let `assignmentPattern` be the `AssignmentPattern` that is covered by `LeftHandSideExpression`.+> 1. Let `rref` be the result of evaluating `AssignmentExpression`.+> 1. Let `rval` be `? GetValue(rref)`.+> 1. Perform `? DestructuringAssignmentEvaluation` of `assignmentPattern` using `rval` as the argument.+> 1. Return `rval`.++Now the `LeftHandSideExpression` (`x`) is not an object literal or an array literal, so we take the if branch in step 1. In step 1 a, we evaluate the left-hand side (`x`) and store the result into `lref`. `o2.foo` is not a function definition, so we don't take the if branch in 1 c, but the else branch in 1 d. There we evaluate `o2.foo` and call `GetValue` on it.

We've merged #332; @marjakh can you please update the post using the mentioned wrapper?

marjakh

comment created time in 3 days

delete branch v8/v8.dev

delete branch : ecmascript-algorithm

delete time in 3 days

push eventv8/v8.dev

Mathias Bynens

commit sha ac974f474ca86f9d1a955285f2abf2ca1a05ccc2

Add `:::ecmascript-algorithm` wrapper with styles (#332) Ref. https://github.com/v8/v8.dev/pull/331#discussion_r380717839.

view details

push time in 3 days

PR merged v8/v8.dev

Add `:::ecmascript-algorithm` wrapper with styles blog cla: yes meta

Ref. https://github.com/v8/v8.dev/pull/331#discussion_r380717839.

cc @marjakh

+55 -18

1 comment

3 changed files

mathiasbynens

pr closed time in 3 days

pull request commentv8/v8.dev

Add `:::ecmascript-algorithm` wrapper with styles

Thanks @mathiasbynens!

mathiasbynens

comment created time in 3 days

Pull request review commentv8/v8.dev

Add `:::ecmascript-algorithm` wrapper with styles

 If an algorithm throws an exception, it means returning a Completion Record with  [`ReturnIfAbrupt(argument)`](https://tc39.es/ecma262/#sec-returnifabrupt) means taking the following steps: +:::ecmascript-algorithm+<!-- markdownlint-disable blanks-around-lists -->

Okay, let's go with this for now, we can always iterate later.

mathiasbynens

comment created time in 3 days

Pull request review commentv8/v8.dev

Add Intl.DisplayNames feature explainer

 languageNames.of('de'); // → '德文' ``` -The following example gets currency names in Simplified Chinese using [ISO-4217 3-letter currency codes](https://www.iso.org/iso-4217-currency-codes.html).+The following example gets currency names in Simplified Chinese using [ISO-4217 3-letter currency codes](https://www.iso.org/iso-4217-currency-codes.html). In languages that have distinct singular and plural forms, the currency names are singular. For plural forms, [Intl.NumberFormat](https://v8.dev/features/intl-numberformat) may be used.
The following example gets currency names in Simplified Chinese using [ISO-4217 3-letter currency codes](https://www.iso.org/iso-4217-currency-codes.html). In languages that have distinct singular and plural forms, the currency names are singular. For plural forms, [`Intl.NumberFormat`](https://v8.dev/features/intl-numberformat) may be used.
syg

comment created time in 4 days

Pull request review commentv8/v8.dev

Add Intl.DisplayNames feature explainer

+---+title: '`Intl.DisplayNames`'+author: 'Shu-yu Guo ([@_shu](https://twitter.com/_shu)) and Frank Tang'+avatars:+  - 'shu-yu-guo'+  - 'frank-tang'+date: 2020-02-13+tags:+  - Intl+  - Node.js 14+description: 'The Intl.DisplayNames API enables localized names of languages, regions, scripts, and currencies.'+---+Web applications that reach a global audience need to show the display names of languages, regions, scripts, and currencies in many different languages. The translations of those names require data, which is available in the [Unicode CLDR](http://cldr.unicode.org/translation/). Packaging the data as part of the application incurs a cost on developer time. Users are likely to prefer consistent translations of language and region names, and keeping that data up to date with the world's geopolitical happenings requires constant maintenance.++Luckily, most JavaScript runtimes already ship and keep up-to-date that very same translation data. The new `Intl.DisplayNames` API gives JavaScript developers direct access to those translations, allowing applications to more easily display localized names.++## Usage examples++The following example shows how to create an `Intl.DisplayNames` object to get region names in English using [ISO-3166 2-letter country codes](https://www.iso.org/iso-3166-country-codes.html).++```js+const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });+regionNames.of('US');+// → 'United States'+regionNames.of('BA');+// → 'Bosnia & Herzegovina'+regionNames.of('MM');+// → 'Myanmar (Burma)'+```++The following example gets language names in Traditional Chinese using [Unicode's language identifier grammar](http://unicode.org/reports/tr35/#Unicode_language_identifier).++```js+const languageNames = new Intl.DisplayNames(['zh-Hant'], { type: 'language' });+languageNames.of('fr');+// → '法文'+languageNames.of('zh');+// → '中文'+languageNames.of('de');+// → '德文'+```++The following example gets currency names in Simplified Chinese using [ISO-4217 3-letter currency codes](https://www.iso.org/iso-4217-currency-codes.html).++```js+const currencyNames = new Intl.DisplayNames(['zh-Hans'], {type: 'currency'});

...which you already did :)

syg

comment created time in 4 days

Pull request review commentv8/v8.dev

Add Intl.DisplayNames feature explainer

+---+title: '`Intl.DisplayNames`'+author: 'Shu-yu Guo ([@_shu](https://twitter.com/_shu)) and Frank Tang'+avatars:+  - 'shu-yu-guo'+  - 'frank-tang'+date: 2020-02-13+tags:+  - Intl+  - Node.js 14+description: 'The Intl.DisplayNames API enables localized names of languages, regions, scripts, and currencies.'+---+Web applications that reach a global audience need to show the display names of languages, regions, scripts, and currencies in many different languages. The translations of those names require data, which is available in the [Unicode CLDR](http://cldr.unicode.org/translation/). Packaging the data as part of the application incurs a cost on developer time. Users are likely to prefer consistent translations of language and region names, and keeping that data up to date with the world's geopolitical happenings requires constant maintenance.++Luckily, most JavaScript runtimes already ship and keep up-to-date that very same translation data. The new `Intl.DisplayNames` API gives JavaScript developers direct access to those translations, allowing applications to more easily display localized names.++## Usage examples++The following example shows how to create an `Intl.DisplayNames` object to get region names in English using [ISO-3166 2-letter country codes](https://www.iso.org/iso-3166-country-codes.html).++```js+const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });+regionNames.of('US');+// → 'United States'+regionNames.of('BA');+// → 'Bosnia & Herzegovina'+regionNames.of('MM');+// → 'Myanmar (Burma)'+```++The following example gets language names in Traditional Chinese using [Unicode's language identifier grammar](http://unicode.org/reports/tr35/#Unicode_language_identifier).++```js+const languageNames = new Intl.DisplayNames(['zh-Hant'], { type: 'language' });+languageNames.of('fr');+// → '法文'+languageNames.of('zh');+// → '中文'+languageNames.of('de');+// → '德文'+```++The following example gets currency names in Simplified Chinese using [ISO-4217 3-letter currency codes](https://www.iso.org/iso-4217-currency-codes.html).++```js+const currencyNames = new Intl.DisplayNames(['zh-Hans'], {type: 'currency'});

Clarification that it's only singular names in the text?

Yeah, if that's the case. Probably worth including a note about NumberFormat (and a link to that other explainer) as well.

syg

comment created time in 4 days

Pull request review commentv8/v8.dev

Add `:::ecmascript-algorithm` wrapper with styles

 If an algorithm throws an exception, it means returning a Completion Record with  [`ReturnIfAbrupt(argument)`](https://tc39.es/ecma262/#sec-returnifabrupt) means taking the following steps: +:::ecmascript-algorithm+<!-- markdownlint-disable blanks-around-lists -->

Is there any way to configure markdownlint to ignore all these instances?

mathiasbynens

comment created time in 4 days

Pull request review commentv8/v8.dev

Add a blog post: Understanding the ECMAScript spec, part 2

+---+title: 'Understanding the ECMAScript spec, part 2'+author: '[Marja Hölttä](https://twitter.com/marjakh), speculative specification spectator'+avatars:+  - marja-holtta+date: 2020-02-11 13:33:37+tags:+  - ECMAScript+description: 'Tutorial on reading the ECMAScript specification'+tweet: ''+---++... where we practice our awesome spec reading skills some more.++## Previous episodes++If you haven't had a look at the previous episodes, now it's a good time to do so!++In [part 1](https://v8.dev/blog/understanding-ecmascript-part-1) we read through a simple method, `Object.prorotype.hasOwnProperty`, and other **abstract operations** it invokes. We familiarized ourselves with the shorhands `?` and `!`related to error handling. We encountered **language types**, **specification types**, **internal slots** and **internal methods**.++## Ready for part 2?++A fun way to get to know the spec is to start with a JavaScript feature we know is there, and find out how it's specified.++We know that properties are looked up in the prototype chain: if an object doesn't have the property we're trying to read, we walk up the prototype chain until we find it (or find an object which no longer has a prototype).++For example:++```javascript+const o1 = {'foo' : 2511};+const o2 = {};+console.log(o2.foo); // undefined+Object.setPrototypeOf(o2, o1);+console.log(o2.foo); // 2511+```++## Where's the prototype walk defined?++Let's try to find out where this behavior is defined. A good place to start is a list of [Object Internal Methods](https://tc39.es/ecma262/#sec-object-internal-methods-and-internal-slots).++There's both `[[GetOwnProperty]]` and `[[Get]]` &mdash; now we're interested in the version that isn't restricted to _own_ properties, so we'll go with `[[Get]]`.++Unfortunately, the [Property Descriptor specification type](https://tc39.es/ecma262/#sec-property-descriptor-specification-type) also has a field called `[[Get]]`, so while browsing the spec for `[[Get]]`, we need to carefully distinguish between the two independent usages.++The internal method `[[Get]]` delegates to `OrdinaryGet`:++> [`[[Get]] ( P, Receiver )`](https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver)+>+> When the `[[Get]]` internal method of `O` is called with property key `P` and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Return `? OrdinaryGet(O, P, Receiver)`.++We'll see shortly that `Receiver` is the value which is used as the **this value** when calling a getter function of an accessor property.++`OrdinaryGet` is defined like this:++> [`OrdinaryGet ( O, P, Receiver )`](https://tc39.es/ecma262/#sec-ordinaryget)+>+> When the abstract operation `OrdinaryGet` is called with Object `O`, property key `P`, and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Assert: `IsPropertyKey(P)` is `true`.+> 2. Let `desc` be `? O.[[GetOwnProperty]](P)`.+> 3. If `desc` is `undefined`, then+> a. Let `parent` be `? O.[[GetPrototypeOf]]()`.+> b. If `parent` is `null`, return `undefined`.+> c. Return `? parent.[[Get]](P, Receiver)`.+> 4. If `IsDataDescriptor(desc)` is `true`, return `desc.[[Value]]`.+> 5. Assert: `IsAccessorDescriptor(desc)` is `true`.+> 6. Let `getter` be `desc.[[Get]]`.+> 7. If `getter` is `undefined`, return `undefined`.+> 8. Return `? Call(getter, Receiver)`.++The prototype chain walk is inside step 3: if we don't find the property as an own property, we recurse into the prototype's `[[Get]]` method.++## What's `Receiver` and where is it coming from?++The `Receiver` parameter is only used in the case of accessor properties in step 8. It's passed as the **this value** when calling the getter function of an accessor property.++`OrdinaryGet` passes the original `Receiver` throughout the recursion, unchanged (step 3 c). Let's find out where the `Receiver` is originally coming from!++Searching for places where `[[Get]]` is called we find an abstract operation `GetValue` which operates on References. Reference is a specification type, consisting of a base value, the reference name and a strict reference flag. In the case of `o2.foo`, the base value is the Object `o2`, the reference name is the String `"foo"` and the strict reference flag is `false`, since the example code is sloppy.++### Side track: References++Side track: A Reference is not a Record, even though it sounds like it could be. It contains three components, which could equally well be expressed as three fixed named values. Here the spec takes a different approach, and defines References as a higher-level data type. This is because of historical reasons.++### Back to `GetValue`++Let's look at how `GetValue` is defined:++> [`GetValue ( V )`](https://tc39.es/ecma262/#sec-getvalue)+>+> 1. `ReturnIfAbrupt(V)`.+> 2. If `Type(V)` is not `Reference`, return `V`.+> 3. Let `base` be `GetBase(V)`.+> 4. If `IsUnresolvableReference(V)` is `true`, throw a `ReferenceError` exception.+> 5. If `IsPropertyReference(V)` is `true`, then+> a. If `HasPrimitiveBase(V)` is `true`, then+> i. Assert: In this case, `base` will never be `undefined` or `null`.+> ii. Set `base` to `! ToObject(base)`.+> b. Return `? base.[[Get]](GetReferencedName(V), GetThisValue(V))`.+> 6. Else,+> a. Assert: `base` is an Environment Record.+> b. Return `? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))`++The reference in our example is `o2.foo` which is a property reference. So we take branch 5. We don't take the branch in 5 a, since the base (`o2`) is not a primitive value (a Boolean, String, Symbol, BigInt or Number).++Then we call `[[Get]]` in step 5 b. The `Receiver` we pass is `GetThisValue(V)`. In this case, it's just the basevalue of the Reference:++> [`GetThisValue( V )`](https://tc39.es/ecma262/#sec-getthisvalue)+>+> 1. Assert: `IsPropertyReference(V)` is `true`.+> 2. If `IsSuperReference(V)` is `true`, then+> a. Return the value of the `thisValue` component of the reference `V`.+> 3. Return `GetBase(V)`.++For `o2.foo`, we don't take the branch in step 2, since it's not a super reference (such as `super.foo`), but we take step 3 and return the base value of the reference which is `o2`.++Piecing everything together, we find out that we set the `Receiver` to be the base of the original reference, and then we keep it unchanged during the prototype chain walk. Finally, if the property we find is an accessor property, we use the `Receiver` as the **this value** when calling it.++In particular, the **this value** inside a getter refers to the original object where we tried to get the property from, not the one where we found the property during the prototype chain walk.++Let's try it out!++```javascript+const o1 = { x: 10, get foo() { return this.x; } };+let o2 = {};+Object.setPrototypeOf(o2, o1);+o2.x = 50;+o2.foo; // will return 50+```++In this example, we have an accessor property called `foo` and we define a getter for it. The getter returns `this.x`.++Then we access `o2.foo` - what does the getter return?++We found out that when we call the getter, the **this value** is the object where we originally tried to get the property from, not the object where we found it. In this case the **this value** is `o2`, not `o1`. We can verify that by checking whether the getter returns `o2.x` or `o1.x`, and indeed, it returns `o2.x`.++(Note that setting `o2.x = 50` adds a property called `x` in `o2` and doesn't overwrite the property `x` in `o1`.)++It works! We were able to predict the behavior of this code snippet based on what we read in the spec.++## Accessing properties - why does it invoke `[[Get]]`?++But where does the spec say that the Object internal method `[[Get]]` will get invoked when accessing a property like `o2.foo`? Surely that has to be defined somewhere. Don't take my word for it!++We found out that the Object internal method `[[Get]]` is called from the abstract operation `GetValue` which operates on References. But where is `GetValue` called from?++### Runtime Semantics++The grammar rules of the spec define the syntax of the language. [Runtime semantics](https://tc39.es/ecma262/#sec-runtime-semantics) define what the syntactic constructs "mean" (how to evaluate them at runtime).++We'll take a deeper look into the grammar rules in a later episode, let's keep it simple for now! In particular, we can ignore the subscripts (`Yield`, `Await` and so on) in the productions for this episode.++(If you're not familiar with [context-free grammars](https://en.wikipedia.org/wiki/Context-free_grammar), it's a good idea to have a look now!)++The following productions describe how a `MemberExpression` looks like:++> [`MemberExpression :`](https://tc39.es/ecma262/#prod-MemberExpression)+>+> `PrimaryExpression`+> `MemberExpression [ Expression ]`+> `MemberExpression . IdentifierName`+> `MemberExpression TemplateLiteral`+> `SuperProperty`+> `MetaProperty`+> `new MemberExpression Arguments`++Here we have 8 productions for `MemberExpression`. A `MemberExpression` can be just a `PrimaryExpression`. Alternatively, a `MemberExpression` can be constructed from another `MemberExpression` and `Expression` by piecing them together: `MemberExpression [ Expression ]`, for example `o2['foo']`. Or it can be `MemberExpression . IdentifierName`, for example `o2.foo` &mdash; this is the production relevant for our example.++Runtime semantics for the production `MemberExpression : MemberExpression . IdentifierName` define the set of steps to take when evaluating it:++> [Runtime Semantics: Evaluation for `MemberExpression : MemberExpression . IdentifierName`](https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation)+>+> 1. Let `baseReference` be the result of evaluating `MemberExpression`.+> 2. Let `baseValue` be `? GetValue(baseReference)`.+> 3. If the code matched by this `MemberExpression` is strict mode code, let `strict` be `true`; else let `strict` be `false`.+> 4. Return `? EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict)`.++The algorithm delegates to the abstract operation `EvaluatePropertyAccessWithIdentifierKey`, so we need to read it too:++> [`EvaluatePropertyAccessWithIdentifierKey( baseValue, identifierName, strict )`](https://tc39.es/ecma262/#sec-evaluate-property-access-with-identifier-key)+>+> The abstract operation `EvaluatePropertyAccessWithIdentifierKey` takes as arguments a value `baseValue`, a Parse Node `identifierName`, and a Boolean argument `strict`. It performs the following steps:+>+> 1. Assert: `identifierName` is an `IdentifierName`+> 2. Let `bv` be `? RequireObjectCoercible(baseValue)`.+> 3. Let `propertyNameString` be `StringValue` of `identifierName`.+> 4. Return a value of type Reference whose base value component is `bv`, whose referenced name component is `propertyNameString`, and whose strict reference flag is `strict`.++That is: `EvaluatePropertyAccessWithIdentifierKey` constructs a Reference which uses the provided `baseValue` as the base, the string value of `identifierName` as the property name, and `strict` as the strict mode flag.++Eventually this Reference gets passed to `GetValue`. This is defined in several places in the spec, depending on how the Reference ends up being used.++### Property access as a parameter++For example, we can use the property access as a parameter.++```javascript+console.log(o2.foo);+```++In this case, the behavior is defined in the runtime semantics of `ArgumentList` production which calls `GetValue` on the argument:++> [Runtime Semantics: ArgumentListEvaluation](https://tc39.es/ecma262/#sec-argument-lists-runtime-semantics-argumentlistevaluation)+>+> `ArgumentList : AssignmentExpression`+>+> 1. Let `ref` be the result of evaluating `AssignmentExpression`.+> 2. Let `arg` be `? GetValue(ref)`.+> 3. Return a List whose sole item is `arg`.++`o2.foo` doesn't look like an `AssignmentExpression` but it is one, so this production is applicable. (Why `o2.foo` is an `AssignmentExpression` will be explained later in this post.)++So, the `AssignmentExpression` is `o2.foo`. `ref`, the result of evaluating `o2.foo`, is the above mentioned Reference. Now we call `GetValue` on it.++### Property access as the right hand side of an assignment++We can also use the property access as a right hand side of an assignment:++```javascript+x = o2.foo;+```++In this case, the behavior is defined in the runtime semantics for the `AssignmentExpression : LeftHandSide = AssignmentExpression` production. Also this ends up calling `GetValue` on the result of evaluating the right hand side `AssignmentExpression`.++> [Runtime Semantics: Evaluation for `AssignmentExpression : LeftHandSideExpression = AssignmentExpression`](https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation)+>+> 1. If `LeftHandSideExpression` is neither an `ObjectLiteral` nor an `ArrayLiteral`, then+>     1. Let `lref` be the result of evaluating `LeftHandSideExpression`.+>     1. `ReturnIfAbrupt(lref)`.+>     1. If `IsAnonymousFunctionDefinition(AssignmentExpression)` and `IsIdentifierRef` of `LeftHandSideExpression` are both `true`, then+>         1. Let `rval` be `NamedEvaluation` of `AssignmentExpression` with argument `GetReferencedName(lref)`.+>     1. Else,+>         1. Let `rref` be the result of evaluating `AssignmentExpression`.+>         1. Let `rval` be `? GetValue(rref)`.+>     1. Perform `? PutValue(lref, rval)`.+>     1. Return `rval`.+> 1. Let `assignmentPattern` be the `AssignmentPattern` that is covered by `LeftHandSideExpression`.+> 1. Let `rref` be the result of evaluating `AssignmentExpression`.+> 1. Let `rval` be `? GetValue(rref)`.+> 1. Perform `? DestructuringAssignmentEvaluation` of `assignmentPattern` using `rval` as the argument.+> 1. Return `rval`.++Now the `LeftHandSideExpression` (`x`) is not an object literal or an array literal, so we take the if branch in step 1. In step 1 a, we evaluate the left-hand side (`x`) and store the result into `lref`. `o2.foo` is not a function definition, so we don't take the if branch in 1 c, but the else branch in 1 d. There we evaluate `o2.foo` and call `GetValue` on it.

@mathiasbynens On the second thought, do you think it would be useful to change styles by default on entire blog?

There already is (and probably will be) lots of quotes from the ECMAScript spec (duh, given the nature of the blog) and it could be nicer to keep nested list styles consistent everywhere.

FWIW this is what I did locally to style this one page and could add this to global CSS instead:

ol > li > ol { list-style-type: lower-alpha; }
ol > li > ol > li > ol { list-style-type: lower-roman; }
marjakh

comment created time in 5 days

Pull request review commentv8/v8.dev

Add a blog post: Understanding the ECMAScript spec, part 2

+---+title: 'Understanding the ECMAScript spec, part 2'+author: '[Marja Hölttä](https://twitter.com/marjakh), speculative specification spectator'+avatars:+  - marja-holtta+date: 2020-02-11 13:33:37+tags:+  - ECMAScript+description: 'Tutorial on reading the ECMAScript specification'+tweet: ''+---++... where we practice our awesome spec reading skills some more.++## Previous episodes++If you haven't had a look at the previous episodes, now it's a good time to do so!++In [part 1](https://v8.dev/blog/understanding-ecmascript-part-1) we read through a simple method, `Object.prorotype.hasOwnProperty`, and other **abstract operations** it invokes. We familiarized ourselves with the shorhands `?` and `!`related to error handling. We encountered **language types**, **specification types**, **internal slots** and **internal methods**.++## Ready for part 2?++A fun way to get to know the spec is to start with a JavaScript feature we know is there, and find out how it's specified.++We know that properties are looked up in the prototype chain: if an object doesn't have the property we're trying to read, we walk up the prototype chain until we find it (or find an object which no longer has a prototype).++For example:++```javascript+const o1 = {'foo' : 2511};+const o2 = {};+console.log(o2.foo); // undefined+Object.setPrototypeOf(o2, o1);+console.log(o2.foo); // 2511+```++## Where's the prototype walk defined?++Let's try to find out where this behavior is defined. A good place to start is a list of [Object Internal Methods](https://tc39.es/ecma262/#sec-object-internal-methods-and-internal-slots).++There's both `[[GetOwnProperty]]` and `[[Get]]` &mdash; now we're interested in the version that isn't restricted to _own_ properties, so we'll go with `[[Get]]`.++Unfortunately, the [Property Descriptor specification type](https://tc39.es/ecma262/#sec-property-descriptor-specification-type) also has a field called `[[Get]]`, so while browsing the spec for `[[Get]]`, we need to carefully distinguish between the two independent usages.++The internal method `[[Get]]` delegates to `OrdinaryGet`:++> [`[[Get]] ( P, Receiver )`](https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver)+>+> When the `[[Get]]` internal method of `O` is called with property key `P` and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Return `? OrdinaryGet(O, P, Receiver)`.++We'll see shortly that `Receiver` is the value which is used as the **this value** when calling a getter function of an accessor property.++`OrdinaryGet` is defined like this:++> [`OrdinaryGet ( O, P, Receiver )`](https://tc39.es/ecma262/#sec-ordinaryget)+>+> When the abstract operation `OrdinaryGet` is called with Object `O`, property key `P`, and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Assert: `IsPropertyKey(P)` is `true`.+> 2. Let `desc` be `? O.[[GetOwnProperty]](P)`.+> 3. If `desc` is `undefined`, then+> a. Let `parent` be `? O.[[GetPrototypeOf]]()`.+> b. If `parent` is `null`, return `undefined`.+> c. Return `? parent.[[Get]](P, Receiver)`.+> 4. If `IsDataDescriptor(desc)` is `true`, return `desc.[[Value]]`.+> 5. Assert: `IsAccessorDescriptor(desc)` is `true`.+> 6. Let `getter` be `desc.[[Get]]`.+> 7. If `getter` is `undefined`, return `undefined`.+> 8. Return `? Call(getter, Receiver)`.++The prototype chain walk is inside step 3: if we don't find the property as an own property, we recurse into the prototype's `[[Get]]` method.++## What's `Receiver` and where is it coming from?++The `Receiver` parameter is only used in the case of accessor properties in step 8. It's passed as the **this value** when calling the getter function of an accessor property.++`OrdinaryGet` passes the original `Receiver` throughout the recursion, unchanged (step 3 c). Let's find out where the `Receiver` is originally coming from!++Searching for places where `[[Get]]` is called we find an abstract operation `GetValue` which operates on References. Reference is a specification type, consisting of a base value, the reference name and a strict reference flag. In the case of `o2.foo`, the base value is the Object `o2`, the reference name is the String `"foo"` and the strict reference flag is `false`, since the example code is sloppy.++### Side track: References++Side track: A Reference is not a Record, even though it sounds like it could be. It contains three components, which could equally well be expressed as three fixed named values. Here the spec takes a different approach, and defines References as a higher-level data type. This is because of historical reasons.++### Back to `GetValue`++Let's look at how `GetValue` is defined:++> [`GetValue ( V )`](https://tc39.es/ecma262/#sec-getvalue)+>+> 1. `ReturnIfAbrupt(V)`.+> 2. If `Type(V)` is not `Reference`, return `V`.+> 3. Let `base` be `GetBase(V)`.+> 4. If `IsUnresolvableReference(V)` is `true`, throw a `ReferenceError` exception.+> 5. If `IsPropertyReference(V)` is `true`, then+> a. If `HasPrimitiveBase(V)` is `true`, then+> i. Assert: In this case, `base` will never be `undefined` or `null`.+> ii. Set `base` to `! ToObject(base)`.+> b. Return `? base.[[Get]](GetReferencedName(V), GetThisValue(V))`.+> 6. Else,+> a. Assert: `base` is an Environment Record.+> b. Return `? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))`++The reference in our example is `o2.foo` which is a property reference. So we take branch 5. We don't take the branch in 5 a, since the base (`o2`) is not a primitive value (a Boolean, String, Symbol, BigInt or Number).++Then we call `[[Get]]` in step 5 b. The `Receiver` we pass is `GetThisValue(V)`. In this case, it's just the basevalue of the Reference:++> [`GetThisValue( V )`](https://tc39.es/ecma262/#sec-getthisvalue)+>+> 1. Assert: `IsPropertyReference(V)` is `true`.+> 2. If `IsSuperReference(V)` is `true`, then+> a. Return the value of the `thisValue` component of the reference `V`.+> 3. Return `GetBase(V)`.++For `o2.foo`, we don't take the branch in step 2, since it's not a super reference (such as `super.foo`), but we take step 3 and return the base value of the reference which is `o2`.++Piecing everything together, we find out that we set the `Receiver` to be the base of the original reference, and then we keep it unchanged during the prototype chain walk. Finally, if the property we find is an accessor property, we use the `Receiver` as the **this value** when calling it.++In particular, the **this value** inside a getter refers to the original object where we tried to get the property from, not the one where we found the property during the prototype chain walk.++Let's try it out!++```javascript+const o1 = { x: 10, get foo() { return this.x; } };+let o2 = {};+Object.setPrototypeOf(o2, o1);+o2.x = 50;+o2.foo; // will return 50+```++In this example, we have an accessor property called `foo` and we define a getter for it. The getter returns `this.x`.++Then we access `o2.foo` - what does the getter return?++We found out that when we call the getter, the **this value** is the object where we originally tried to get the property from, not the object where we found it. In this case the **this value** is `o2`, not `o1`. We can verify that by checking whether the getter returns `o2.x` or `o1.x`, and indeed, it returns `o2.x`.++(Note that setting `o2.x = 50` adds a property called `x` in `o2` and doesn't overwrite the property `x` in `o1`.)++It works! We were able to predict the behavior of this code snippet based on what we read in the spec.++## Accessing properties - why does it invoke `[[Get]]`?++But where does the spec say that the Object internal method `[[Get]]` will get invoked when accessing a property like `o2.foo`? Surely that has to be defined somewhere. Don't take my word for it!++We found out that the Object internal method `[[Get]]` is called from the abstract operation `GetValue` which operates on References. But where is `GetValue` called from?++### Runtime Semantics++The grammar rules of the spec define the syntax of the language. [Runtime semantics](https://tc39.es/ecma262/#sec-runtime-semantics) define what the syntactic constructs "mean" (how to evaluate them at runtime).++We'll take a deeper look into the grammar rules in a later episode, let's keep it simple for now! In particular, we can ignore the subscripts (`Yield`, `Await` and so on) in the productions for this episode.++(If you're not familiar with [context-free grammars](https://en.wikipedia.org/wiki/Context-free_grammar), it's a good idea to have a look now!)++The following productions describe how a `MemberExpression` looks like:++> [`MemberExpression :`](https://tc39.es/ecma262/#prod-MemberExpression)+>+> `PrimaryExpression`+> `MemberExpression [ Expression ]`+> `MemberExpression . IdentifierName`+> `MemberExpression TemplateLiteral`+> `SuperProperty`+> `MetaProperty`+> `new MemberExpression Arguments`++Here we have 8 productions for `MemberExpression`. A `MemberExpression` can be just a `PrimaryExpression`. Alternatively, a `MemberExpression` can be constructed from another `MemberExpression` and `Expression` by piecing them together: `MemberExpression [ Expression ]`, for example `o2['foo']`. Or it can be `MemberExpression . IdentifierName`, for example `o2.foo` &mdash; this is the production relevant for our example.++Runtime semantics for the production `MemberExpression : MemberExpression . IdentifierName` define the set of steps to take when evaluating it:++> [Runtime Semantics: Evaluation for `MemberExpression : MemberExpression . IdentifierName`](https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation)+>+> 1. Let `baseReference` be the result of evaluating `MemberExpression`.+> 2. Let `baseValue` be `? GetValue(baseReference)`.+> 3. If the code matched by this `MemberExpression` is strict mode code, let `strict` be `true`; else let `strict` be `false`.+> 4. Return `? EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict)`.++The algorithm delegates to the abstract operation `EvaluatePropertyAccessWithIdentifierKey`, so we need to read it too:++> [`EvaluatePropertyAccessWithIdentifierKey( baseValue, identifierName, strict )`](https://tc39.es/ecma262/#sec-evaluate-property-access-with-identifier-key)+>+> The abstract operation `EvaluatePropertyAccessWithIdentifierKey` takes as arguments a value `baseValue`, a Parse Node `identifierName`, and a Boolean argument `strict`. It performs the following steps:+>+> 1. Assert: `identifierName` is an `IdentifierName`+> 2. Let `bv` be `? RequireObjectCoercible(baseValue)`.+> 3. Let `propertyNameString` be `StringValue` of `identifierName`.+> 4. Return a value of type Reference whose base value component is `bv`, whose referenced name component is `propertyNameString`, and whose strict reference flag is `strict`.++That is: `EvaluatePropertyAccessWithIdentifierKey` constructs a Reference which uses the provided `baseValue` as the base, the string value of `identifierName` as the property name, and `strict` as the strict mode flag.++Eventually this Reference gets passed to `GetValue`. This is defined in several places in the spec, depending on how the Reference ends up being used.++### Property access as a parameter++For example, we can use the property access as a parameter.++```javascript+console.log(o2.foo);+```++In this case, the behavior is defined in the runtime semantics of `ArgumentList` production which calls `GetValue` on the argument:++> [Runtime Semantics: ArgumentListEvaluation](https://tc39.es/ecma262/#sec-argument-lists-runtime-semantics-argumentlistevaluation)+>+> `ArgumentList : AssignmentExpression`+>+> 1. Let `ref` be the result of evaluating `AssignmentExpression`.+> 2. Let `arg` be `? GetValue(ref)`.+> 3. Return a List whose sole item is `arg`.++`o2.foo` doesn't look like an `AssignmentExpression` but it is one, so this production is applicable. (Why `o2.foo` is an `AssignmentExpression` will be explained later in this post.)++So, the `AssignmentExpression` is `o2.foo`. `ref`, the result of evaluating `o2.foo`, is the above mentioned Reference. Now we call `GetValue` on it.++### Property access as the right hand side of an assignment++We can also use the property access as a right hand side of an assignment:++```javascript+x = o2.foo;+```++In this case, the behavior is defined in the runtime semantics for the `AssignmentExpression : LeftHandSide = AssignmentExpression` production. Also this ends up calling `GetValue` on the result of evaluating the right hand side `AssignmentExpression`.++> [Runtime Semantics: Evaluation for `AssignmentExpression : LeftHandSideExpression = AssignmentExpression`](https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation)+>+> 1. If `LeftHandSideExpression` is neither an `ObjectLiteral` nor an `ArrayLiteral`, then+>     1. Let `lref` be the result of evaluating `LeftHandSideExpression`.+>     1. `ReturnIfAbrupt(lref)`.+>     1. If `IsAnonymousFunctionDefinition(AssignmentExpression)` and `IsIdentifierRef` of `LeftHandSideExpression` are both `true`, then+>         1. Let `rval` be `NamedEvaluation` of `AssignmentExpression` with argument `GetReferencedName(lref)`.+>     1. Else,+>         1. Let `rref` be the result of evaluating `AssignmentExpression`.+>         1. Let `rval` be `? GetValue(rref)`.+>     1. Perform `? PutValue(lref, rval)`.+>     1. Return `rval`.+> 1. Let `assignmentPattern` be the `AssignmentPattern` that is covered by `LeftHandSideExpression`.+> 1. Let `rref` be the result of evaluating `AssignmentExpression`.+> 1. Let `rval` be `? GetValue(rref)`.+> 1. Perform `? DestructuringAssignmentEvaluation` of `assignmentPattern` using `rval` as the argument.+> 1. Return `rval`.++Now the `LeftHandSideExpression` (`x`) is not an object literal or an array literal, so we take the if branch in step 1. In step 1 a, we evaluate the left-hand side (`x`) and store the result into `lref`. `o2.foo` is not a function definition, so we don't take the if branch in 1 c, but the else branch in 1 d. There we evaluate `o2.foo` and call `GetValue` on it.

(update based on the chat: found a better solution using <style> on the page to get consistent formatting; still not perfect, because, well, it uses <style> on the page, so looking into something more viable in markdown-it)

marjakh

comment created time in 5 days

Pull request review commentv8/v8.dev

Add a blog post: Understanding the ECMAScript spec, part 2

+---+title: 'Understanding the ECMAScript spec, part 2'+author: '[Marja Hölttä](https://twitter.com/marjakh), speculative specification spectator'+avatars:+  - marja-holtta+date: 2020-02-11 13:33:37+tags:+  - ECMAScript+description: 'Tutorial on reading the ECMAScript specification'+tweet: ''+---++... where we practice our awesome spec reading skills some more.++## Previous episodes++If you haven't had a look at the previous episodes, now it's a good time to do so!++In [part 1](https://v8.dev/blog/understanding-ecmascript-part-1) we read through a simple method, `Object.prorotype.hasOwnProperty`, and other **abstract operations** it invokes. We familiarized ourselves with the shorhands `?` and `!`related to error handling. We encountered **language types**, **specification types**, **internal slots** and **internal methods**.++## Ready for part 2?++A fun way to get to know the spec is to start with a JavaScript feature we know is there, and find out how it's specified.++We know that properties are looked up in the prototype chain: if an object doesn't have the property we're trying to read, we walk up the prototype chain until we find it (or find an object which no longer has a prototype).++For example:++```javascript+const o1 = {'foo' : 2511};+const o2 = {};+console.log(o2.foo); // undefined+Object.setPrototypeOf(o2, o1);+console.log(o2.foo); // 2511+```++## Where's the prototype walk defined?++Let's try to find out where this behavior is defined. A good place to start is a list of [Object Internal Methods](https://tc39.es/ecma262/#sec-object-internal-methods-and-internal-slots).++There's both `[[GetOwnProperty]]` and `[[Get]]` &mdash; now we're interested in the version that isn't restricted to _own_ properties, so we'll go with `[[Get]]`.++Unfortunately, the [Property Descriptor specification type](https://tc39.es/ecma262/#sec-property-descriptor-specification-type) also has a field called `[[Get]]`, so while browsing the spec for `[[Get]]`, we need to carefully distinguish between the two independent usages.++The internal method `[[Get]]` delegates to `OrdinaryGet`:++> [`[[Get]] ( P, Receiver )`](https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver)+>+> When the `[[Get]]` internal method of `O` is called with property key `P` and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Return `? OrdinaryGet(O, P, Receiver)`.++We'll see shortly that `Receiver` is the value which is used as the **this value** when calling a getter function of an accessor property.++`OrdinaryGet` is defined like this:++> [`OrdinaryGet ( O, P, Receiver )`](https://tc39.es/ecma262/#sec-ordinaryget)+>+> When the abstract operation `OrdinaryGet` is called with Object `O`, property key `P`, and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Assert: `IsPropertyKey(P)` is `true`.+> 2. Let `desc` be `? O.[[GetOwnProperty]](P)`.+> 3. If `desc` is `undefined`, then+> a. Let `parent` be `? O.[[GetPrototypeOf]]()`.+> b. If `parent` is `null`, return `undefined`.+> c. Return `? parent.[[Get]](P, Receiver)`.+> 4. If `IsDataDescriptor(desc)` is `true`, return `desc.[[Value]]`.+> 5. Assert: `IsAccessorDescriptor(desc)` is `true`.+> 6. Let `getter` be `desc.[[Get]]`.+> 7. If `getter` is `undefined`, return `undefined`.+> 8. Return `? Call(getter, Receiver)`.++The prototype chain walk is inside step 3: if we don't find the property as an own property, we recurse into the prototype's `[[Get]]` method.++## What's `Receiver` and where is it coming from?++The `Receiver` parameter is only used in the case of accessor properties in step 8. It's passed as the **this value** when calling the getter function of an accessor property.++`OrdinaryGet` passes the original `Receiver` throughout the recursion, unchanged (step 3 c). Let's find out where the `Receiver` is originally coming from!++Searching for places where `[[Get]]` is called we find an abstract operation `GetValue` which operates on References. Reference is a specification type, consisting of a base value, the reference name and a strict reference flag. In the case of `o2.foo`, the base value is the Object `o2`, the reference name is the String `"foo"` and the strict reference flag is `false`, since the example code is sloppy.++### Side track: References++Side track: A Reference is not a Record, even though it sounds like it could be. It contains three components, which could equally well be expressed as three fixed named values. Here the spec takes a different approach, and defines References as a higher-level data type. This is because of historical reasons.++### Back to `GetValue`++Let's look at how `GetValue` is defined:++> [`GetValue ( V )`](https://tc39.es/ecma262/#sec-getvalue)+>+> 1. `ReturnIfAbrupt(V)`.+> 2. If `Type(V)` is not `Reference`, return `V`.+> 3. Let `base` be `GetBase(V)`.+> 4. If `IsUnresolvableReference(V)` is `true`, throw a `ReferenceError` exception.+> 5. If `IsPropertyReference(V)` is `true`, then+> a. If `HasPrimitiveBase(V)` is `true`, then+> i. Assert: In this case, `base` will never be `undefined` or `null`.+> ii. Set `base` to `! ToObject(base)`.+> b. Return `? base.[[Get]](GetReferencedName(V), GetThisValue(V))`.+> 6. Else,+> a. Assert: `base` is an Environment Record.+> b. Return `? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))`++The reference in our example is `o2.foo` which is a property reference. So we take branch 5. We don't take the branch in 5 a, since the base (`o2`) is not a primitive value (a Boolean, String, Symbol, BigInt or Number).++Then we call `[[Get]]` in step 5 b. The `Receiver` we pass is `GetThisValue(V)`. In this case, it's just the basevalue of the Reference:++> [`GetThisValue( V )`](https://tc39.es/ecma262/#sec-getthisvalue)+>+> 1. Assert: `IsPropertyReference(V)` is `true`.+> 2. If `IsSuperReference(V)` is `true`, then+> a. Return the value of the `thisValue` component of the reference `V`.+> 3. Return `GetBase(V)`.++For `o2.foo`, we don't take the branch in step 2, since it's not a super reference (such as `super.foo`), but we take step 3 and return the base value of the reference which is `o2`.++Piecing everything together, we find out that we set the `Receiver` to be the base of the original reference, and then we keep it unchanged during the prototype chain walk. Finally, if the property we find is an accessor property, we use the `Receiver` as the **this value** when calling it.++In particular, the **this value** inside a getter refers to the original object where we tried to get the property from, not the one where we found the property during the prototype chain walk.++Let's try it out!++```javascript+const o1 = { x: 10, get foo() { return this.x; } };+let o2 = {};+Object.setPrototypeOf(o2, o1);+o2.x = 50;+o2.foo; // will return 50+```++In this example, we have an accessor property called `foo` and we define a getter for it. The getter returns `this.x`.++Then we access `o2.foo` - what does the getter return?++We found out that when we call the getter, the **this value** is the object where we originally tried to get the property from, not the object where we found it. In this case the **this value** is `o2`, not `o1`. We can verify that by checking whether the getter returns `o2.x` or `o1.x`, and indeed, it returns `o2.x`.++(Note that setting `o2.x = 50` adds a property called `x` in `o2` and doesn't overwrite the property `x` in `o1`.)++It works! We were able to predict the behavior of this code snippet based on what we read in the spec.++## Accessing properties - why does it invoke `[[Get]]`?++But where does the spec say that the Object internal method `[[Get]]` will get invoked when accessing a property like `o2.foo`? Surely that has to be defined somewhere. Don't take my word for it!++We found out that the Object internal method `[[Get]]` is called from the abstract operation `GetValue` which operates on References. But where is `GetValue` called from?++### Runtime Semantics++The grammar rules of the spec define the syntax of the language. [Runtime semantics](https://tc39.es/ecma262/#sec-runtime-semantics) define what the syntactic constructs "mean" (how to evaluate them at runtime).++We'll take a deeper look into the grammar rules in a later episode, let's keep it simple for now! In particular, we can ignore the subscripts (`Yield`, `Await` and so on) in the productions for this episode.++(If you're not familiar with [context-free grammars](https://en.wikipedia.org/wiki/Context-free_grammar), it's a good idea to have a look now!)++The following productions describe how a `MemberExpression` looks like:++> [`MemberExpression :`](https://tc39.es/ecma262/#prod-MemberExpression)+>+> `PrimaryExpression`+> `MemberExpression [ Expression ]`+> `MemberExpression . IdentifierName`+> `MemberExpression TemplateLiteral`+> `SuperProperty`+> `MetaProperty`+> `new MemberExpression Arguments`++Here we have 8 productions for `MemberExpression`. A `MemberExpression` can be just a `PrimaryExpression`. Alternatively, a `MemberExpression` can be constructed from another `MemberExpression` and `Expression` by piecing them together: `MemberExpression [ Expression ]`, for example `o2['foo']`. Or it can be `MemberExpression . IdentifierName`, for example `o2.foo` &mdash; this is the production relevant for our example.++Runtime semantics for the production `MemberExpression : MemberExpression . IdentifierName` define the set of steps to take when evaluating it:++> [Runtime Semantics: Evaluation for `MemberExpression : MemberExpression . IdentifierName`](https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation)+>+> 1. Let `baseReference` be the result of evaluating `MemberExpression`.+> 2. Let `baseValue` be `? GetValue(baseReference)`.+> 3. If the code matched by this `MemberExpression` is strict mode code, let `strict` be `true`; else let `strict` be `false`.+> 4. Return `? EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict)`.++The algorithm delegates to the abstract operation `EvaluatePropertyAccessWithIdentifierKey`, so we need to read it too:++> [`EvaluatePropertyAccessWithIdentifierKey( baseValue, identifierName, strict )`](https://tc39.es/ecma262/#sec-evaluate-property-access-with-identifier-key)+>+> The abstract operation `EvaluatePropertyAccessWithIdentifierKey` takes as arguments a value `baseValue`, a Parse Node `identifierName`, and a Boolean argument `strict`. It performs the following steps:+>+> 1. Assert: `identifierName` is an `IdentifierName`+> 2. Let `bv` be `? RequireObjectCoercible(baseValue)`.+> 3. Let `propertyNameString` be `StringValue` of `identifierName`.+> 4. Return a value of type Reference whose base value component is `bv`, whose referenced name component is `propertyNameString`, and whose strict reference flag is `strict`.++That is: `EvaluatePropertyAccessWithIdentifierKey` constructs a Reference which uses the provided `baseValue` as the base, the string value of `identifierName` as the property name, and `strict` as the strict mode flag.++Eventually this Reference gets passed to `GetValue`. This is defined in several places in the spec, depending on how the Reference ends up being used.++### Property access as a parameter++For example, we can use the property access as a parameter.++```javascript+console.log(o2.foo);+```++In this case, the behavior is defined in the runtime semantics of `ArgumentList` production which calls `GetValue` on the argument:++> [Runtime Semantics: ArgumentListEvaluation](https://tc39.es/ecma262/#sec-argument-lists-runtime-semantics-argumentlistevaluation)+>+> `ArgumentList : AssignmentExpression`+>+> 1. Let `ref` be the result of evaluating `AssignmentExpression`.+> 2. Let `arg` be `? GetValue(ref)`.+> 3. Return a List whose sole item is `arg`.++`o2.foo` doesn't look like an `AssignmentExpression` but it is one, so this production is applicable. (Why `o2.foo` is an `AssignmentExpression` will be explained later in this post.)++So, the `AssignmentExpression` is `o2.foo`. `ref`, the result of evaluating `o2.foo`, is the above mentioned Reference. Now we call `GetValue` on it.++### Property access as the right hand side of an assignment++We can also use the property access as a right hand side of an assignment:++```javascript+x = o2.foo;+```++In this case, the behavior is defined in the runtime semantics for the `AssignmentExpression : LeftHandSide = AssignmentExpression` production. Also this ends up calling `GetValue` on the result of evaluating the right hand side `AssignmentExpression`.++> [Runtime Semantics: Evaluation for `AssignmentExpression : LeftHandSideExpression = AssignmentExpression`](https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation)+>+> 1. If `LeftHandSideExpression` is neither an `ObjectLiteral` nor an `ArrayLiteral`, then+>     1. Let `lref` be the result of evaluating `LeftHandSideExpression`.+>     1. `ReturnIfAbrupt(lref)`.+>     1. If `IsAnonymousFunctionDefinition(AssignmentExpression)` and `IsIdentifierRef` of `LeftHandSideExpression` are both `true`, then+>         1. Let `rval` be `NamedEvaluation` of `AssignmentExpression` with argument `GetReferencedName(lref)`.+>     1. Else,+>         1. Let `rref` be the result of evaluating `AssignmentExpression`.+>         1. Let `rval` be `? GetValue(rref)`.+>     1. Perform `? PutValue(lref, rval)`.+>     1. Return `rval`.+> 1. Let `assignmentPattern` be the `AssignmentPattern` that is covered by `LeftHandSideExpression`.+> 1. Let `rref` be the result of evaluating `AssignmentExpression`.+> 1. Let `rval` be `? GetValue(rref)`.+> 1. Perform `? DestructuringAssignmentEvaluation` of `assignmentPattern` using `rval` as the argument.+> 1. Return `rval`.++Now the `LeftHandSideExpression` (`x`) is not an object literal or an array literal, so we take the if branch in step 1. In step 1 a, we evaluate the left-hand side (`x`) and store the result into `lref`. `o2.foo` is not a function definition, so we don't take the if branch in 1 c, but the else branch in 1 d. There we evaluate `o2.foo` and call `GetValue` on it.

Looks like this will require either changing our CSS or using inline HTML like:

<ol type="a">
<li>123
<li>456
</ol>

which is not as "good" as CSS version, but consistently renders as

<ol type="a"> <li>123 <li>456 </ol>

even on Github.

marjakh

comment created time in 5 days

Pull request review commentv8/v8.dev

Add Intl.DisplayNames feature explainer

+---+title: '`Intl.DisplayNames`'+author: 'Shu-yu Guo ([@_shu](https://twitter.com/_shu)) and Frank Tang'+avatars:+  - 'shu-yu-guo'+  - 'frank-tang'+date: 2020-02-13+tags:+  - Intl+  - Node.js 14

That... wasn't very obvious, but okay :)

syg

comment created time in 5 days

Pull request review commentv8/v8.dev

Add Intl.DisplayNames feature explainer

+---+title: '`Intl.DisplayNames`'+author: 'Shu-yu Guo ([@_shu](https://twitter.com/_shu)) and Frank Tang'+avatars:+  - 'shu-yu-guo'+  - 'frank-tang'+date: 2020-02-13+tags:+  - Intl+  - Node.js 14

If you open any of the posts containing that tag in the source, you can actually see that such tags with a space also seem to have silently broken the parser and both them and any following tags are not rendered on the pages.

For example: https://github.com/v8/v8.dev/blob/f880711d0ebd70413e3a3cecb1e7f3dbaaa969ab/src/features/intl-relativetimeformat.md#L7-L10

contains Intl, Node.js 12 and io19 in the source, but

https://v8.dev/features/intl-relativetimeformat

renders only Intl.

syg

comment created time in 5 days

create barnchv8/v8.dev

branch : gh-actions

created branch time in 5 days

push eventv8/v8.dev

Kruithne

commit sha f109f1d76b13936e838309259a4a895ba6b0368f

Fix misplaced feature support header (#330)

view details

push time in 5 days

PR merged v8/v8.dev

Fix misplaced feature support header cla: yes

The feature support header for https://v8.dev/features/function-tostring was incorrectly using the text from https://v8.dev/features/optional-catch-binding. This fixes it.

+1 -1

6 comments

1 changed file

Kruithne

pr closed time in 5 days

pull request commentv8/v8.dev

Fix misplaced feature support header

Thank you!

Kruithne

comment created time in 5 days

Pull request review commentv8/v8.dev

Add a blog post: Understanding the ECMAScript spec, part 2

+---+title: 'Understanding the ECMAScript spec, part 2'+author: '[Marja Hölttä](https://twitter.com/marjakh), speculative specification spectator'+avatars:+  - marja-holtta+date: 2020-02-11 13:33:37+tags:+  - ECMAScript+description: 'Tutorial on reading the ECMAScript specification'+tweet: ''+---++... where we practice our awesome spec reading skills some more.++## Previous episodes++If you haven't had a look at the previous episodes, now it's a good time to do so!++In [part 1](https://v8.dev/blog/understanding-ecmascript-part-1) we read through a simple method, `Object.prorotype.hasOwnProperty`, and other **abstract operations** it invokes. We familiarized ourselves with the shorhands `?` and `!`related to error handling. We encountered **language types**, **specification types**, **internal slots** and **internal methods**.++## Ready for part 2?++A fun way to get to know the spec is to start with a JavaScript feature we know is there, and find out how it's specified.++We know that properties are looked up in the prototype chain: if an object doesn't have the property we're trying to read, we walk up the prototype chain until we find it (or find an object which no longer has a prototype).++For example:++```javascript+const o1 = {'foo' : 2511};+const o2 = {};+console.log(o2.foo); // undefined+Object.setPrototypeOf(o2, o1);+console.log(o2.foo); // 2511+```++## Where's the prototype walk defined?++Let's try to find out where this behavior is defined. A good place to start is a list of [Object Internal Methods](https://tc39.es/ecma262/#sec-object-internal-methods-and-internal-slots).++There's both `[[GetOwnProperty]]` and `[[Get]]` &mdash; now we're interested in the version that isn't restricted to _own_ properties, so we'll go with `[[Get]]`.++Unfortunately, the [Property Descriptor specification type](https://tc39.es/ecma262/#sec-property-descriptor-specification-type) also has a field called `[[Get]]`, so while browsing the spec for `[[Get]]`, we need to carefully distinguish between the two independent usages.++The internal method `[[Get]]` delegates to `OrdinaryGet`:++> [`[[Get]] ( P, Receiver )`](https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver)+>+> When the `[[Get]]` internal method of `O` is called with property key `P` and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Return `? OrdinaryGet(O, P, Receiver)`.++We'll see shortly that `Receiver` is the value which is used as the **this value** when calling a getter function of an accessor property.++`OrdinaryGet` is defined like this:++> [`OrdinaryGet ( O, P, Receiver )`](https://tc39.es/ecma262/#sec-ordinaryget)+>+> When the abstract operation `OrdinaryGet` is called with Object `O`, property key `P`, and ECMAScript language value `Receiver`, the following steps are taken:+>+> 1. Assert: `IsPropertyKey(P)` is `true`.+> 2. Let `desc` be `? O.[[GetOwnProperty]](P)`.+> 3. If `desc` is `undefined`, then+> a. Let `parent` be `? O.[[GetPrototypeOf]]()`.+> b. If `parent` is `null`, return `undefined`.+> c. Return `? parent.[[Get]](P, Receiver)`.+> 4. If `IsDataDescriptor(desc)` is `true`, return `desc.[[Value]]`.+> 5. Assert: `IsAccessorDescriptor(desc)` is `true`.+> 6. Let `getter` be `desc.[[Get]]`.+> 7. If `getter` is `undefined`, return `undefined`.+> 8. Return `? Call(getter, Receiver)`.++The prototype chain walk is inside step 3: if we don't find the property as an own property, we recurse into the prototype's `[[Get]]` method.++## What's `Receiver` and where is it coming from?++The `Receiver` parameter is only used in the case of accessor properties in step 8. It's passed as the **this value** when calling the getter function of an accessor property.++`OrdinaryGet` passes the original `Receiver` throughout the recursion, unchanged (step 3 c). Let's find out where the `Receiver` is originally coming from!++Searching for places where `[[Get]]` is called we find an abstract operation `GetValue` which operates on References. Reference is a specification type, consisting of a base value, the reference name and a strict reference flag. In the case of `o2.foo`, the base value is the Object `o2`, the reference name is the String `"foo"` and the strict reference flag is `false`, since the example code is sloppy.++### Side track: References++Side track: A Reference is not a Record, even though it sounds like it could be. It contains three components, which could equally well be expressed as three fixed named values. Here the spec takes a different approach, and defines References as a higher-level data type. This is because of historical reasons.++### Back to `GetValue`++Let's look at how `GetValue` is defined:++> [`GetValue ( V )`](https://tc39.es/ecma262/#sec-getvalue)+>+> 1. `ReturnIfAbrupt(V)`.+> 2. If `Type(V)` is not `Reference`, return `V`.+> 3. Let `base` be `GetBase(V)`.+> 4. If `IsUnresolvableReference(V)` is `true`, throw a `ReferenceError` exception.+> 5. If `IsPropertyReference(V)` is `true`, then+> a. If `HasPrimitiveBase(V)` is `true`, then+> i. Assert: In this case, `base` will never be `undefined` or `null`.+> ii. Set `base` to `! ToObject(base)`.+> b. Return `? base.[[Get]](GetReferencedName(V), GetThisValue(V))`.+> 6. Else,+> a. Assert: `base` is an Environment Record.+> b. Return `? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))`++The reference in our example is `o2.foo` which is a property reference. So we take branch 5. We don't take the branch in 5 a, since the base (`o2`) is not a primitive value (a Boolean, String, Symbol, BigInt or Number).++Then we call `[[Get]]` in step 5 b. The `Receiver` we pass is `GetThisValue(V)`. In this case, it's just the basevalue of the Reference:++> [`GetThisValue( V )`](https://tc39.es/ecma262/#sec-getthisvalue)+>+> 1. Assert: `IsPropertyReference(V)` is `true`.+> 2. If `IsSuperReference(V)` is `true`, then+> a. Return the value of the `thisValue` component of the reference `V`.+> 3. Return `GetBase(V)`.++For `o2.foo`, we don't take the branch in step 2, since it's not a super reference (such as `super.foo`), but we take step 3 and return the base value of the reference which is `o2`.++Piecing everything together, we find out that we set the `Receiver` to be the base of the original reference, and then we keep it unchanged during the prototype chain walk. Finally, if the property we find is an accessor property, we use the `Receiver` as the **this value** when calling it.++In particular, the **this value** inside a getter refers to the original object where we tried to get the property from, not the one where we found the property during the prototype chain walk.++Let's try it out!++```javascript+const o1 = { x: 10, get foo() { return this.x; } };+let o2 = {};+Object.setPrototypeOf(o2, o1);+o2.x = 50;+o2.foo; // will return 50+```++In this example, we have an accessor property called `foo` and we define a getter for it. The getter returns `this.x`.++Then we access `o2.foo` - what does the getter return?++We found out that when we call the getter, the **this value** is the object where we originally tried to get the property from, not the object where we found it. In this case the **this value** is `o2`, not `o1`. We can verify that by checking whether the getter returns `o2.x` or `o1.x`, and indeed, it returns `o2.x`.++(Note that setting `o2.x = 50` adds a property called `x` in `o2` and doesn't overwrite the property `x` in `o1`.)++It works! We were able to predict the behavior of this code snippet based on what we read in the spec.++## Accessing properties - why does it invoke `[[Get]]`?++But where does the spec say that the Object internal method `[[Get]]` will get invoked when accessing a property like `o2.foo`? Surely that has to be defined somewhere. Don't take my word for it!++We found out that the Object internal method `[[Get]]` is called from the abstract operation `GetValue` which operates on References. But where is `GetValue` called from?++### Runtime Semantics++The grammar rules of the spec define the syntax of the language. [Runtime semantics](https://tc39.es/ecma262/#sec-runtime-semantics) define what the syntactic constructs "mean" (how to evaluate them at runtime).++We'll take a deeper look into the grammar rules in a later episode, let's keep it simple for now! In particular, we can ignore the subscripts (`Yield`, `Await` and so on) in the productions for this episode.++(If you're not familiar with [context-free grammars](https://en.wikipedia.org/wiki/Context-free_grammar), it's a good idea to have a look now!)++The following productions describe how a `MemberExpression` looks like:++> [`MemberExpression :`](https://tc39.es/ecma262/#prod-MemberExpression)+>+> `PrimaryExpression`+> `MemberExpression [ Expression ]`+> `MemberExpression . IdentifierName`+> `MemberExpression TemplateLiteral`+> `SuperProperty`+> `MetaProperty`+> `new MemberExpression Arguments`++Here we have 8 productions for `MemberExpression`. A `MemberExpression` can be just a `PrimaryExpression`. Alternatively, a `MemberExpression` can be constructed from another `MemberExpression` and `Expression` by piecing them together: `MemberExpression [ Expression ]`, for example `o2['foo']`. Or it can be `MemberExpression . IdentifierName`, for example `o2.foo` &mdash; this is the production relevant for our example.++Runtime semantics for the production `MemberExpression : MemberExpression . IdentifierName` define the set of steps to take when evaluating it:++> [Runtime Semantics: Evaluation for `MemberExpression : MemberExpression . IdentifierName`](https://tc39.es/ecma262/#sec-property-accessors-runtime-semantics-evaluation)+>+> 1. Let `baseReference` be the result of evaluating `MemberExpression`.+> 2. Let `baseValue` be `? GetValue(baseReference)`.+> 3. If the code matched by this `MemberExpression` is strict mode code, let `strict` be `true`; else let `strict` be `false`.+> 4. Return `? EvaluatePropertyAccessWithIdentifierKey(baseValue, IdentifierName, strict)`.++The algorithm delegates to the abstract operation `EvaluatePropertyAccessWithIdentifierKey`, so we need to read it too:++> [`EvaluatePropertyAccessWithIdentifierKey( baseValue, identifierName, strict )`](https://tc39.es/ecma262/#sec-evaluate-property-access-with-identifier-key)+>+> The abstract operation `EvaluatePropertyAccessWithIdentifierKey` takes as arguments a value `baseValue`, a Parse Node `identifierName`, and a Boolean argument `strict`. It performs the following steps:+>+> 1. Assert: `identifierName` is an `IdentifierName`+> 2. Let `bv` be `? RequireObjectCoercible(baseValue)`.+> 3. Let `propertyNameString` be `StringValue` of `identifierName`.+> 4. Return a value of type Reference whose base value component is `bv`, whose referenced name component is `propertyNameString`, and whose strict reference flag is `strict`.++That is: `EvaluatePropertyAccessWithIdentifierKey` constructs a Reference which uses the provided `baseValue` as the base, the string value of `identifierName` as the property name, and `strict` as the strict mode flag.++Eventually this Reference gets passed to `GetValue`. This is defined in several places in the spec, depending on how the Reference ends up being used.++### Property access as a parameter++For example, we can use the property access as a parameter.++```javascript+console.log(o2.foo);+```++In this case, the behavior is defined in the runtime semantics of `ArgumentList` production which calls `GetValue` on the argument:++> [Runtime Semantics: ArgumentListEvaluation](https://tc39.es/ecma262/#sec-argument-lists-runtime-semantics-argumentlistevaluation)+>+> `ArgumentList : AssignmentExpression`+>+> 1. Let `ref` be the result of evaluating `AssignmentExpression`.+> 2. Let `arg` be `? GetValue(ref)`.+> 3. Return a List whose sole item is `arg`.++`o2.foo` doesn't look like an `AssignmentExpression` but it is one, so this production is applicable. (Why `o2.foo` is an `AssignmentExpression` will be explained later in this post.)++So, the `AssignmentExpression` is `o2.foo`. `ref`, the result of evaluating `o2.foo`, is the above mentioned Reference. Now we call `GetValue` on it.++### Property access as the right hand side of an assignment++We can also use the property access as a right hand side of an assignment:++```javascript+x = o2.foo;+```++In this case, the behavior is defined in the runtime semantics for the `AssignmentExpression : LeftHandSide = AssignmentExpression` production. Also this ends up calling `GetValue` on the result of evaluating the right hand side `AssignmentExpression`.++> [Runtime Semantics: Evaluation for `AssignmentExpression : LeftHandSideExpression = AssignmentExpression`](https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation)+>+> 1. If `LeftHandSideExpression` is neither an `ObjectLiteral` nor an `ArrayLiteral`, then+>     1. Let `lref` be the result of evaluating `LeftHandSideExpression`.+>     1. `ReturnIfAbrupt(lref)`.+>     1. If `IsAnonymousFunctionDefinition(AssignmentExpression)` and `IsIdentifierRef` of `LeftHandSideExpression` are both `true`, then+>         1. Let `rval` be `NamedEvaluation` of `AssignmentExpression` with argument `GetReferencedName(lref)`.+>     1. Else,+>         1. Let `rref` be the result of evaluating `AssignmentExpression`.+>         1. Let `rval` be `? GetValue(rref)`.+>     1. Perform `? PutValue(lref, rval)`.+>     1. Return `rval`.+> 1. Let `assignmentPattern` be the `AssignmentPattern` that is covered by `LeftHandSideExpression`.+> 1. Let `rref` be the result of evaluating `AssignmentExpression`.+> 1. Let `rval` be `? GetValue(rref)`.+> 1. Perform `? DestructuringAssignmentEvaluation` of `assignmentPattern` using `rval` as the argument.+> 1. Return `rval`.++Now the `LeftHandSideExpression` (`x`) is not an object literal or an array literal, so we take the if branch in step 1. In step 1 a, we evaluate the left-hand side (`x`) and store the result into `lref`. `o2.foo` is not a function definition, so we don't take the if branch in 1 c, but the else branch in 1 d. There we evaluate `o2.foo` and call `GetValue` on it.

In step 1 a

It's not rendered as a, so this can be confusing. The nested list style above should be changed correspondingly.

marjakh

comment created time in 5 days

Pull request review commentv8/v8.dev

Add a blog post: Understanding the ECMAScript spec, part 2

+---+title: 'Understanding the ECMAScript spec, part 2'+author: '[Marja Hölttä](https://twitter.com/marjakh), speculative specification spectator'+avatars:+  - marja-holtta+date: 2020-02-11 13:33:37+tags:+  - ECMAScript+description: 'Tutorial on reading the ECMAScript specification'+tweet: ''+---++... where we practice our awesome spec reading skills some more.++## Previous episodes++If you haven't had a look at the previous episodes, now it's a good time to do so!++In [part 1](https://v8.dev/blog/understanding-ecmascript-part-1) we read through a simple method, `Object.prorotype.hasOwnProperty`, and other **abstract operations** it invokes. We familiarized ourselves with the shorhands `?` and `!`related to error handling. We encountered **language types**, **specification types**, **internal slots** and **internal methods**.
In [part 1](https://v8.dev/blog/understanding-ecmascript-part-1) we read through a simple method — `Object.prorotype.hasOwnProperty` — and **abstract operations** it invokes. We familiarized ourselves with the shorthands `?` and `!` related to error handling. We encountered **language types**, **specification types**, **internal slots** and **internal methods**.
marjakh

comment created time in 5 days

Pull request review commentv8/v8.dev

Add Intl.DisplayNames feature explainer

+---+title: '`Intl.DisplayNames`'+author: 'Shu-yu Guo ([@_shu](https://twitter.com/_shu)) and Frank Tang'+avatars:+  - 'shu-yu-guo'+  - 'frank-tang'+date: 2020-02-13+tags:+  - Intl+  - Node.js 14+description: 'The Intl.DisplayNames API enables localized names of languages, regions, scripts, and currencies.'+---+Web applications that reach a global audience need to show the display names of languages, regions, scripts, and currencies in many different languages. The translations of those names require data, which is available in the [Unicode CLDR](http://cldr.unicode.org/translation/). Packaging the data as part of the application incurs a cost on developer time. Users are likely to prefer consistent translations of language and region names, and keeping that data up to date with the world's geopolitical happenings requires constant maintenance.++Luckily, most JavaScript runtimes already ship and keep up-to-date that very same translation data. The new `Intl.DisplayNames` API gives JavaScript developers direct access to those translations, allowing applications to more easily display localized names.++## Usage examples++The following example shows how to create an `Intl.DisplayNames` object to get region names in English using [ISO-3166 2-letter country codes](https://www.iso.org/iso-3166-country-codes.html).++```js+const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });+regionNames.of('US');+// → 'United States'+regionNames.of('BA');+// → 'Bosnia & Herzegovina'+regionNames.of('MM');+// → 'Myanmar (Burma)'+```++The following example gets language names in Traditional Chinese using [Unicode's language identifier grammar](http://unicode.org/reports/tr35/#Unicode_language_identifier).++```js+const languageNames = new Intl.DisplayNames(['zh-Hant'], { type: 'language' });+languageNames.of('fr');+// → '法文'+languageNames.of('zh');+// → '中文'+languageNames.of('de');+// → '德文'+```++The following example gets currency names in Simplified Chinese using [ISO-4217 3-letter currency codes](https://www.iso.org/iso-4217-currency-codes.html).++```js+const currencyNames = new Intl.DisplayNames(['zh-Hans'], {type: 'currency'});

Are these for singular currency names of plural ones? Is there a way to customise this via options? (seems like an obvious question reader would ask)

syg

comment created time in 5 days

Pull request review commentv8/v8.dev

Add Intl.DisplayNames feature explainer

+---+title: '`Intl.DisplayNames`'+author: 'Shu-yu Guo ([@_shu](https://twitter.com/_shu)) and Frank Tang'+avatars:+  - 'shu-yu-guo'+  - 'frank-tang'+date: 2020-02-13+tags:+  - Intl+  - Node.js 14

I don't think this is a valid tag (with spaces), and on the previous Intl post we just included Intl - let's do the same here?

syg

comment created time in 5 days

startedgimli-rs/object

started time in 5 days

push eventRReverser/object

Ingvar Stepanyan

commit sha c052369391533e4a1379437a4f265ca4f870ab8e

Enhance Wasm symbol reading Add support for: - Symbols for imports (with Dynamic scope). - "Virtual" file symbols to delimit imports from main file. - Symbols for local functions (with Compilation scope and real address and size). - Symbols for exports. - Text (functions) and Data (everything else) symbol kinds. - Start section converted to an entry address. - Symbols for local functions. - Predefined section kinds based on the section code. Note that if a function is exported, then it will appear under its exported names with a Dynamic scope. Otherwise it's a local function and will appear with its debug name from the "names" section and a Compilation scope. Also note that this adds support for fully built Wasm modules, but not for dynamic linking yet. That one will require adding more code for parsing relocation info and can be done in future in a separate PR. Fixes #196.

view details

push time in 5 days

pull request commentgimli-rs/object

Enhance Wasm symbol reading

Also nm example output for comparison.

Before:

Debugging symbols:
0000000000000000 0000000000000000 ? f
0000000000000001 0000000000000000 ? __wasm_call_ctors
0000000000000002 0000000000000000 ? h
0000000000000003 0000000000000000 ? g
0000000000000004 0000000000000000 ? get_v
0000000000000005 0000000000000000 ? set_v
0000000000000006 0000000000000000 ? get_r

Dynamic symbols:

After:

Debugging symbols:
0000000000000000 0000000000000000 ? f
0000000000000000 0000000000000000 ? memory
00000000000000d9 0000000000000002 T __wasm_call_ctors
0000000000000000 0000000000000000 ? __data_end
0000000000000000 0000000000000000 ? __global_base
0000000000000000 0000000000000000 ? __heap_base
0000000000000000 0000000000000000 ? __dso_handle
00000000000000dc 000000000000001e T h
0000000000000107 0000000000000016 T get_v
000000000000011e 0000000000000035 T set_v
0000000000000154 000000000000000f T get_r
00000000000000dc 000000000000001e T h2
00000000000000fb 000000000000000b t g

Dynamic symbols:
RReverser

comment created time in 5 days

push eventRReverser/object

Ingvar Stepanyan

commit sha 116630f7b1d0a22f5b1ccfaf514dfce8d4e8ff7f

Fix std -> core APIs in wasm.rs

view details

push time in 5 days

starteddtolnay/reflect

started time in 5 days

pull request commentgimli-rs/object

Enhance Wasm symbol reading

I slightly enhanced the example from the issue report to:

static const char *v = "test";
static const char *const r = "abcd";

extern int f();

static int g() {
	return 42;
}

int h() {
	return f() + g();
}

int h2() __attribute__((weak, alias("h")));

const char *get_v() {
	return v;
}

void set_v(const char *new_v) {
	v = new_v;
}

const char *get_r() {
	return r;
}

objdump result before this change:

1: Section { name: "<type>", address: 0, size: 12, kind: Unknown }
2: Section { name: "<import>", address: 0, size: 9, kind: Unknown }
3: Section { name: "<function>", address: 0, size: 7, kind: Unknown }
4: Section { name: "<table>", address: 0, size: 5, kind: Unknown }
5: Section { name: "<memory>", address: 0, size: 3, kind: Unknown }
6: Section { name: "<global>", address: 0, size: 33, kind: Unknown }
7: Section { name: "<export>", address: 0, size: 121, kind: Unknown }
10: Section { name: "<code>", address: 0, size: 140, kind: Unknown }
11: Section { name: "<data>", address: 0, size: 27, kind: Unknown }
0: Section { name: ".debug_info", address: 0, size: 202, kind: Unknown }
0: Section { name: ".debug_macinfo", address: 0, size: 1, kind: Unknown }
0: Section { name: ".debug_ranges", address: 0, size: 48, kind: Unknown }
0: Section { name: ".debug_abbrev", address: 0, size: 143, kind: Unknown }
0: Section { name: ".debug_line", address: 0, size: 156, kind: Unknown }
0: Section { name: ".debug_str", address: 0, size: 144, kind: Unknown }
0: Section { name: "name", address: 0, size: 52, kind: Unknown }
0: Section { name: "producers", address: 0, size: 83, kind: Unknown }
0: Symbol { name: Some("f"), address: 0, size: 0, kind: Text, section: Unknown, weak: false, scope: Unknown, flags: None }
1: Symbol { name: Some("__wasm_call_ctors"), address: 1, size: 0, kind: Text, section: Unknown, weak: false, scope: Unknown, flags: None }
2: Symbol { name: Some("h"), address: 2, size: 0, kind: Text, section: Unknown, weak: false, scope: Unknown, flags: None }
3: Symbol { name: Some("g"), address: 3, size: 0, kind: Text, section: Unknown, weak: false, scope: Unknown, flags: None }
4: Symbol { name: Some("get_v"), address: 4, size: 0, kind: Text, section: Unknown, weak: false, scope: Unknown, flags: None }
5: Symbol { name: Some("set_v"), address: 5, size: 0, kind: Text, section: Unknown, weak: false, scope: Unknown, flags: None }
6: Symbol { name: Some("get_r"), address: 6, size: 0, kind: Text, section: Unknown, weak: false, scope: Unknown, flags: None }

After this change:

1: Section { name: "<type>", address: 0, size: 12, kind: Metadata }
2: Section { name: "<import>", address: 0, size: 9, kind: Linker }
3: Section { name: "<function>", address: 0, size: 7, kind: Metadata }
4: Section { name: "<table>", address: 0, size: 5, kind: UninitializedData }
5: Section { name: "<memory>", address: 0, size: 3, kind: UninitializedData }
6: Section { name: "<global>", address: 0, size: 33, kind: Data }
7: Section { name: "<export>", address: 0, size: 121, kind: Linker }
10: Section { name: "<code>", address: 0, size: 140, kind: Text }
11: Section { name: "<data>", address: 0, size: 27, kind: Data }
0: Section { name: ".debug_info", address: 0, size: 202, kind: Other }
0: Section { name: ".debug_macinfo", address: 0, size: 1, kind: Other }
0: Section { name: ".debug_ranges", address: 0, size: 48, kind: Other }
0: Section { name: ".debug_abbrev", address: 0, size: 143, kind: Other }
0: Section { name: ".debug_line", address: 0, size: 156, kind: Other }
0: Section { name: ".debug_str", address: 0, size: 144, kind: Other }
0: Section { name: "name", address: 0, size: 52, kind: Other }
0: Section { name: "producers", address: 0, size: 83, kind: Other }
0: Symbol { name: Some("env"), address: 0, size: 0, kind: File, section: None, weak: false, scope: Dynamic, flags: None }
1: Symbol { name: Some("f"), address: 0, size: 0, kind: Text, section: Section(SectionIndex(2)), weak: false, scope: Dynamic, flags: None }
2: Symbol { name: None, address: 0, size: 0, kind: File, section: None, weak: false, scope: Compilation, flags: None }
3: Symbol { name: Some("memory"), address: 0, size: 0, kind: Data, section: Section(SectionIndex(7)), weak: false, scope: Dynamic, flags: None }
4: Symbol { name: Some("__wasm_call_ctors"), address: 217, size: 2, kind: Text, section: Section(SectionIndex(10)), weak: false, scope: Dynamic, flags: None }
5: Symbol { name: Some("__data_end"), address: 0, size: 0, kind: Data, section: Section(SectionIndex(7)), weak: false, scope: Dynamic, flags: None }
6: Symbol { name: Some("__global_base"), address: 0, size: 0, kind: Data, section: Section(SectionIndex(7)), weak: false, scope: Dynamic, flags: None }
7: Symbol { name: Some("__heap_base"), address: 0, size: 0, kind: Data, section: Section(SectionIndex(7)), weak: false, scope: Dynamic, flags: None }
8: Symbol { name: Some("__dso_handle"), address: 0, size: 0, kind: Data, section: Section(SectionIndex(7)), weak: false, scope: Dynamic, flags: None }
9: Symbol { name: Some("h"), address: 220, size: 30, kind: Text, section: Section(SectionIndex(10)), weak: false, scope: Dynamic, flags: None }
10: Symbol { name: Some("get_v"), address: 263, size: 22, kind: Text, section: Section(SectionIndex(10)), weak: false, scope: Dynamic, flags: None }
11: Symbol { name: Some("set_v"), address: 286, size: 53, kind: Text, section: Section(SectionIndex(10)), weak: false, scope: Dynamic, flags: None }
12: Symbol { name: Some("get_r"), address: 340, size: 15, kind: Text, section: Section(SectionIndex(10)), weak: false, scope: Dynamic, flags: None }
13: Symbol { name: Some("h2"), address: 220, size: 30, kind: Text, section: Section(SectionIndex(10)), weak: false, scope: Dynamic, flags: None }
14: Symbol { name: Some("g"), address: 251, size: 11, kind: Text, section: Section(SectionIndex(10)), weak: false, scope: Compilation, flags: None }
RReverser

comment created time in 5 days

PR opened gimli-rs/object

Enhance Wasm symbol reading

Add support for:

  • Symbols for imports (with Dynamic scope).
  • "Virtual" file symbols to delimit imports from main file.
  • Symbols for local functions (with Compilation scope).
  • Symbols for exports.
  • Text (functions) and Data (everything else) symbol kinds.
  • Start section converted to an entry address.
  • Symbols for local functions.
  • Predefined section kinds based on the section code.

Note that if a function is exported, then it will appear under its exported names with a Dynamic scope. Otherwise it's a local function and will appear with its debug name from the "names" section and a Compilation scope.

Also note that this adds support for fully built Wasm modules, but not for dynamic linking yet. That one will require adding more code for parsing relocation info and can be done in future in a separate PR.

Fixes #196.

+258 -77

0 comment

1 changed file

pr created time in 5 days

create barnchRReverser/object

branch : better-wasm-symbols

created branch time in 5 days

issue commentrust-analyzer/rust-analyzer

Can't disable the "workspace loaded" notification

Okay, yeah, I actually hunted down a copy of ra-lsp that was loading from .../.vscode/extensions/..., but for some reason didn't show up on the list of installed extensions and still ran (and showed some conflict errors in DevTools console of VSCode).

Removing it seems to have gotten settings UI & JSON into a saner state.

RReverser

comment created time in 6 days

issue commentrust-analyzer/rust-analyzer

Can't disable the "workspace loaded" notification

We renamed it from ra-lsp to rust-analyzer about a month ago, and the update should have cleaned up the old one, but perhaps it didn't?

I mean, the settings are in the rust-analyzer namespace and the installed extension is called that way too...

image

might I ask you, please, to open the command palette with Ctrl+Shift+P, write Toggle Developer Tools and press enter, then open Console tab and send its contents here? The effective config that we use should be printed there under Using configuration: If there is nothing like that there, you are most likely using an old version of our extension...

It shows up correctly I think:

image

RReverser

comment created time in 6 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha 150e4c323ad775eaae0ca8a1cee74c4038985e45

Bump Cargo version

view details

push time in 6 days

push eventRReverser/cow-utils-rs

Christopher Serr

commit sha 2fb5410200d1c07029a56f580292eff4ab846643

Implement support for no_std * Implement support for no_std * Disable no_std in doctests on stable Rust See https://github.com/RReverser/cow-utils-rs/pull/1#issuecomment-586973518. * Rename `alloc` import to `std` This is to avoid confusion between link docs and regular types. Co-authored-by: Ingvar Stepanyan <me@rreverser.com>

view details

push time in 6 days

PR merged RReverser/cow-utils-rs

Implement support for no_std

It's a pretty simple fix.

+10 -2

3 comments

2 changed files

CryZe

pr closed time in 6 days

issue commentrust-analyzer/rust-analyzer

Can't disable the "workspace loaded" notification

There's no setting for it (we should remove it if there is). You need to configure it like this.

Btw, I've tried this as well, and still getting the notification on each load :(

image

RReverser

comment created time in 6 days

issue commentrust-analyzer/rust-analyzer

Can't disable the "workspace loaded" notification

The JSON settings editor displays it in gray, but the graphical one probably does nothing.

It doesn't show it in grey even in JSON for me: image

And toggling the option doesn't make it disappear in the UI.

For what it's worth, the extension version is 0.2.20200211-dev which seems fresh enough.

RReverser

comment created time in 6 days

Pull request review commentRReverser/cow-utils-rs

Implement Support for no_std

+#![no_std]

Thanks.

CryZe

comment created time in 6 days

Pull request review commentRReverser/cow-utils-rs

Implement Support for no_std

 pub trait Pattern<'s> { macro_rules! impl_pattern { 	($ty:ty $(where $($bound:tt)*)?) => { 		impl<'s $(, $($bound)*)?> Pattern<'s> for $ty {-			type MatchIndices = std::str::MatchIndices<'s, Self>;+			type MatchIndices = core::str::MatchIndices<'s, Self>;

I've changed the extern crate reference to extern crate alloc as std - it seems less confusing and more consistent that way and allows to keep all std:: references as-is.

CryZe

comment created time in 6 days

push eventCryZe/cow-utils-rs

Ingvar Stepanyan

commit sha f12749bc8955fa4d623e31508ec6eed7e7082c6d

Rename `alloc` import to `std` This is to avoid confusion between link docs and regular types.

view details

push time in 6 days

push eventCryZe/cow-utils-rs

Ingvar Stepanyan

commit sha 91eb7ad54e09ed6f33a0b95cb2885bb0691b31db

Disable no_std in doctests on stable Rust See https://github.com/RReverser/cow-utils-rs/pull/1#issuecomment-586973518.

view details

push time in 6 days

pull request commentRReverser/cow-utils-rs

Implement Support for no_std

So yeah, the error is essentially #52243 and seems fixed on nightly. For now, let's just go with an attribute like above.

CryZe

comment created time in 6 days

startedRReverser/cow-utils-rs

started time in 7 days

pull request commentRReverser/cow-utils-rs

Implement Support for no_std

When testing there's some weird problem where it says it can't find the global allocator. It doesn't cause the tests to fail, but it still shows it. No idea how to get rid of that.

I guess for now you could use something like #![cfg_attr(not(doctest), no_std)]?

CryZe

comment created time in 7 days

Pull request review commentRReverser/cow-utils-rs

Implement Support for no_std

 pub trait Pattern<'s> { macro_rules! impl_pattern { 	($ty:ty $(where $($bound:tt)*)?) => { 		impl<'s $(, $($bound)*)?> Pattern<'s> for $ty {-			type MatchIndices = std::str::MatchIndices<'s, Self>;+			type MatchIndices = core::str::MatchIndices<'s, Self>;

Do references in doc comments need to be updated as well? (I don't know how / whether anyone builds docs with no_std)

CryZe

comment created time in 7 days

Pull request review commentRReverser/cow-utils-rs

Implement Support for no_std

+#![no_std]

Will this work with std as well? I thought in the past crates needed to have a separate Cargo feature for this mode?

CryZe

comment created time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha 85883670f6b1403e2e2f57e6fc95491626fdd939

Add some badges

view details

push time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha 1e3e4d88f921ac738112b5399546c877d103b07f

Add perf section

view details

push time in 7 days

startedtailhook/cpu-time

started time in 7 days

issue commentrust-analyzer/rust-analyzer

Can't disable the "workspace loaded" notification

Well the settings clearly exists in the UI and has existed for a while now (it's been at least half a year since I enabled it), so it seems better to fix it rather than remove altogether.

RReverser

comment created time in 7 days

issue openedrust-analyzer/rust-analyzer

Can't disable the "workspace loaded" notification

I've had "workspace loaded" notification disabled in settings for a while now, and keep trying to update rust-analyzer hoping that this was a temporary bug, but doesn't seem so as notification keeps appearing on every single load:

image image

created time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha 4470707f698ab275d6ec7c2a627c13fd52172cb0

Update job names

view details

Ingvar Stepanyan

commit sha 75dc3b07391429c637d259785315c09e3c444b11

Add simple .replace benchmark

view details

push time in 7 days

issue commentactions-rs/meta

Add `rustfmt-check`

provides information that can't be usually fixed by a machine

Lots (most?) of the suggestions can actually be fixed with cargo fix, so I'd argue same reasoning should apply.

And, either way, since we already have a cargo fmt action that displays issues, I'd argue that improving visibility by showing these issues inline could be great.

JP-Ellis

comment created time in 7 days

create barnchRReverser/cow-utils-rs

branch : master

created branch time in 7 days

created repositoryRReverser/cow-replace-rs

Copy-on-write string utilities for Rust

created time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha 7279d249cd0c7a51b939484a2232ba730b00d7ea

Remove benchmark action

view details

push time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha c5965ae3536fe3874df7485161dfff58f9d7625b

Rename and update benchmark It has to be called "benchmark" for the action to work.

view details

push time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha a4bb8456991ceffad828b5bc07914d39bfe2dd98

Update rust.yml

view details

push time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha 9692e8ea5eb00ef873fd46abde4e4249eb762866

Add simple .replace benchmark

view details

push time in 7 days

push eventRReverser/cow-utils-rs

Ingvar Stepanyan

commit sha a3d76fa25dda37cc324da70c2fe0e1aa487505ce

Update job names; add criterion.rs job

view details

push time in 7 days

PublicEvent

delete branch RReverser/rust

delete branch : wasi-fs-copy

delete time in 7 days

pull request commentrust-lang/rust

Fix std::fs::copy on WASI target

Thanks @KodrAus!

RReverser

comment created time in 7 days

pull request commentDefinitelyTyped/DefinitelyTyped

fix(estree): declaration should not be undefined

Same thing for that, especially with something as specific as estree I would rather break on upgrade than letting new flags pass through.

I can certainly see how that would be useful on the consumer side, but I'm not sure excluding undefined would help here. Even if you exclude it, it still won't help you to catch new flags / properties on nodes. The only way to do that is to manually review node types on definition upgrades.

bodinsamuel

comment created time in 9 days

issue commentWebAssembly/tool-conventions

Build ID Section for WASM

Just as a counter-point, one downside of an embedded id seems to be precisely that it would usually survive destructive operations on the code.

That is, if code is post-processed by a tool similar to wasm-opt or wasm-bindgen, and if that tool can't correctly update DWARF information, then the build id would remain the same even though the code has changed and no longer matches the debug info. In this case you as a consumer (Sentry or otherwise) explicitly don't want such debug info to be matched and used.

Arguably, every such tool should either support DWARF or be able to at least change build ID to some new unique value, but it seems that hashing of code section would alleviate this concern even more naturally.

mitsuhiko

comment created time in 10 days

pull request commentrust-lang/rust

[WIP] Fix std::fs::copy on WASI target

I wanted to verify that this actually compiles as expected, since CI doesn't seem to try to do that on a PR; now verified and should be good to go (well, at least ready for review 😊).

r? @alexcrichton

RReverser

comment created time in 11 days

create barnchRReverser/rust

branch : wasi-fs-copy

created branch time in 11 days

push eventRReverser/rust

Ingvar Stepanyan

commit sha 8fb8bb4b3ff25570a7a9b105c1a569bb2307f25f

Fix std::fs::copy on WASI target Previously `std::fs::copy` on wasm32-wasi would reuse code from the `sys_common` module and would successfully copy contents of the file just to fail right before closing it. This was happening because `sys_common::copy` tries to copy permissions of the file, but permissions are not a thing in WASI (at least yet) and `set_permissions` is implemented as an unconditional runtime error. This change instead adds a custom working implementation of `std::fs::copy` (like Rust already has on some other targets) that doesn't try to call `set_permissions` and is essentially a thin wrapper around `std::io::copy`. Fixes #68560.

view details

push time in 11 days

PR opened rust-lang/rust

Fix std::fs::copy on WASI target

Previously std::fs::copy on wasm32-wasi would reuse code from the sys_common module and would successfully copy contents of the file just to fail right before closing it.

This was happening because sys_common::copy tries to copy permissions of the file, but permissions are not a thing in WASI (at least yet) and set_permissions is implemented as an unconditional runtime error.

This change instead adds a custom working implementation of std::fs::copy (like Rust already has on some other targets) that doesn't try to call set_permissions and is essentially a thin wrapper around std::io::copy.

Fixes #68560.

+7 -1

0 comment

1 changed file

pr created time in 11 days

issue commentrust-lang/rust

Suggestion: no-op set_permissions for WASI

I see; WASI SDK conditionally excludes chmod for WASI target during compilation, and I suppose that's what Rust wants to avoid and instead simulates with a runtime error. Fair enough.

In that case, would you be open to adding a specific implementation of std::fs::copy for WASI target that just uses std::io::copy but doesn't set permissions? There is no direct analogue for it in the wasi-libc anyway, and it would solve this specific API function without changing the rest.

RReverser

comment created time in 11 days

issue commentrust-lang/rust

Suggestion: no-op set_permissions for WASI

Ping @alexcrichton @fitzgen?

RReverser

comment created time in 12 days

issue commentrust-lang/rust

debuginfo: How to (ideally) represent reference and pointer types in DWARF

This is a very old and long and it's been a while since I looked at details, but I'd like to point out that

That is, does Rust have the concept of a mut i32 at the type level, for example?

No. mut is part of reference types, no more.

it not entirely true, or at least, not any different from the situation in C / C++.

Aside from references, Rust also has mutable and immutable variables, parameters and so on, just like C / C++ does. So when one says that Rust doesn't have mut i32 at the type level, same can be said about const uint32_t at the type level in C / C++, because in both cases they describe the actual slot, pointer or a reference and not the value itself.

And yet, even though C / C++ has comparable type semantics, it already has an established DWARF representation for these different types - by using the earlier mentioned "constifying newtypes".

One thing that was brought up and still remains true is that for Rust such representation is potentially more wasteful, because immutable types in Rust are much more popular than in C / C++ due to the flipped defaults.

This might still be true, but on the other hand DWARF representation is fairly compact, and it would be worth measuring first whether introducing a new attribute really saves any noticeable amount of space compared to a separate type ref (which is essentially just a type tag + a reference to the inner type).

For now, it would be great to unblock this issue and implement at least the suboptimal-but-already-supported-in-most-tools representation for immutable vs mutable references, and then we can iterate on it in future PRs.

michaelwoerister

comment created time in 12 days

issue commentmicrosoft/TypeScript

When trying to use mapped tuples as rest parameters error 'A rest parameter must be of an array type' given

@OxleyS I don't think that's the case; at least it doesn't explain why a workaround with an intermediate generic type works (see my example).

Roaders

comment created time in 13 days

delete branch v8/v8.dev

delete branch : fix-understanding-ecmascript-part-1

delete time in 15 days

push eventv8/v8.dev

Marja Hölttä

commit sha 19739df98c59311928753443fdda1f896b19c885

Minor fixes to the blog post Understanding ECMAScript part 1. (#328) * Minor fixes to the blog post Understanding ECMAScript part 1. Co-authored-by: Mathias Bynens <mathias@qiwi.be>

view details

push time in 15 days

more