oj_windows 3.16.15 → 3.17.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -0
- data/README.md +168 -164
- data/ext/oj_windows/extconf.rb +11 -5
- data/ext/oj_windows/mem.c +31 -17
- data/ext/oj_windows/oj.h +6 -0
- data/ext/oj_windows/parse.c +49 -1
- data/ext/oj_windows/parser.c +79 -10
- data/ext/oj_windows/reader.c +2 -0
- data/ext/oj_windows/rxclass.c +1 -1
- data/ext/oj_windows/safe.c +230 -0
- data/ext/oj_windows/safe.h +79 -0
- data/ext/oj_windows/simd.h +46 -0
- data/ext/oj_windows/sparse.c +3 -0
- data/ext/oj_windows/usual.c +4 -1
- data/lib/oj_windows/version.rb +4 -4
- data/pages/InstallOptions.md +14 -4
- metadata +12 -15
- data/lib/oj/active_support_helper.rb +0 -39
- data/lib/oj/bag.rb +0 -95
- data/lib/oj/easy_hash.rb +0 -52
- data/lib/oj/error.rb +0 -21
- data/lib/oj/json.rb +0 -188
- data/lib/oj/mimic.rb +0 -301
- data/lib/oj/saj.rb +0 -80
- data/lib/oj/schandler.rb +0 -143
- data/lib/oj/state.rb +0 -135
- data/lib/oj/version.rb +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed00cf974105c81c2e38ca66a5a00bcf6d6e32106764537fdbc58264cf96912f
|
|
4
|
+
data.tar.gz: c9440ab13621b80ffa95fef72a56c02dc362c1282172c6676d5445b53a6a1648
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bb72bfd23933e0e0dbe2e2e58f9a6eb6855fca6f5832f3e1b5b7abb7f716dd618f6dbf90150d539677cbb03f6ba76f523b25a60aabc6f02a691cdc9a2e05e821
|
|
7
|
+
data.tar.gz: 7e7bfc7b9376a3ab6fb164ce8c0d85d10faed4ab9dd63d5ee455311aa3f293f8f3640b4dd6146d2c32368fd29f7b924dcd788b06616832de7c0333ebb51f71ee
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,79 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `oj_windows` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [3.17.2.1] - 2026-05-29
|
|
6
|
+
|
|
7
|
+
Fork revision based on upstream Oj 3.17.2. The version is `3.17.2.1` (not plain
|
|
8
|
+
`3.17.2`) because this carries upstream's parser feature set through 3.17.2 plus
|
|
9
|
+
the MSVC/SIMD adaptations below; it is not a byte-identical rebase of 3.17.2.
|
|
10
|
+
|
|
11
|
+
### Performance
|
|
12
|
+
- Enabled SIMD string scanning under MSVC. `simd.h` previously gated SSE on the
|
|
13
|
+
GCC/Clang `__SSE2__`/`__SSE4_2__` feature macros, which `cl.exe` never defines,
|
|
14
|
+
so the scalar scanner was always used on the only supported platform. SSE2 is
|
|
15
|
+
now enabled by default on x86_64 (~20–25% faster parsing on string-heavy
|
|
16
|
+
payloads). Added MSVC shims for the GCC builtins used by the SSE scanners
|
|
17
|
+
(`__builtin_prefetch`/`__builtin_expect`/`__builtin_ctz`).
|
|
18
|
+
- The SSE4.2 (PCMPESTRI) scanner is also compiled and selectable, but SSE2 is the
|
|
19
|
+
default because PCMPESTRI is slower on common microarchitectures.
|
|
20
|
+
- Added a `--disable-simd` build option and an `OJ_SCAN=scalar|sse2|sse42` runtime
|
|
21
|
+
override (replacing the previously non-functional `--with-sse42` flag).
|
|
22
|
+
|
|
23
|
+
### Security / robustness (ported from upstream Oj 3.16.16–3.17.2)
|
|
24
|
+
- `Oj::Parser` (the "usual" parser) now validates that the document is complete:
|
|
25
|
+
incomplete literals (`tru`, `nul`, `n`, …) and unclosed arrays/objects (`[1,2`,
|
|
26
|
+
`{"a":1`) are rejected instead of being silently accepted. Ported upstream's
|
|
27
|
+
`validate_document_end` (raises `EncodingError`/`Oj::ParserError` with
|
|
28
|
+
"expected …" / "… is not closed"). `test_parser_usual.rb#test_nil` was updated
|
|
29
|
+
to match the stricter, upstream behavior.
|
|
30
|
+
- Added the **`Oj::Parser.safe`** parser (upstream 3.17.0): builds Ruby objects
|
|
31
|
+
like `:usual` but enforces configurable limits on untrusted input —
|
|
32
|
+
`:max_hash_size`, `:max_array_size`, `:max_depth`, `:max_total_elements` —
|
|
33
|
+
raising `Oj::Parser::ValidationError` subclasses (`HashSizeError`,
|
|
34
|
+
`ArraySizeError`, `DepthError`, `TotalElementsError`). Ported `safe.c`/`safe.h`.
|
|
35
|
+
- Added the upstream 3.17.2 "extreme sizes" key-length guard: object keys longer
|
|
36
|
+
than 32,000 bytes now raise instead of overflowing the `int16_t` key length.
|
|
37
|
+
- Fixed an uninitialized-pointer dereference in the streaming parser: `sparse.c`
|
|
38
|
+
never set `ni.pi`, but `oj_num_as_value` dereferences `ni->pi->err_class` on the
|
|
39
|
+
invalid-float path. Initialized `ni.pi` at all three number sites (matches
|
|
40
|
+
upstream).
|
|
41
|
+
- Note: the non-Windows file-read partial-read fix (#1004) is not reachable on
|
|
42
|
+
MSVC (that path is `#if !IS_WINDOWS`); the Windows-reachable `Oj::Parser#file`
|
|
43
|
+
read was fixed separately (see below).
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- `mem.c` (the `MEM_DEBUG` allocator) no longer fails to compile on MSVC: it now
|
|
47
|
+
uses a Windows `SRWLOCK` (which has a static initializer) instead of an
|
|
48
|
+
unguarded `pthread_mutex_t`.
|
|
49
|
+
- `Oj::Parser#file` captured the `read()` result in an unsigned `size_t`; on a
|
|
50
|
+
read error (`-1`) this wrapped to `SIZE_MAX`, causing an out-of-bounds write
|
|
51
|
+
and making the error branch unreachable. It now uses a signed count, handles
|
|
52
|
+
errors/EOF correctly, and closes the file descriptor.
|
|
53
|
+
- Guarded the remaining unconditional `<sys/types.h>` includes (`reader.c`,
|
|
54
|
+
`rxclass.c`) and added a guarded `ssize_t` fallback for MSVC.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
- Removed the dead, byte-identical `lib/oj/` duplicate tree from the gem package;
|
|
58
|
+
`lib/oj_windows/` is the only tree that is ever loaded.
|
|
59
|
+
- gemspec now credits Peter Ohler and states the relationship to upstream Oj
|
|
60
|
+
(oj_windows replaces, and cannot be co-installed with, the `oj` gem).
|
|
61
|
+
- Build scripts (`package_install.bat`, `compile.bat`, `build_install.bat`) locate
|
|
62
|
+
Visual Studio via `vswhere` (and put the Installer dir on PATH so vcvars runs
|
|
63
|
+
cleanly) and derive the gem filename from `Oj::VERSION` instead of hardcoding a
|
|
64
|
+
VS path or version number.
|
|
65
|
+
- Added a GitHub Actions CI workflow (`.github/workflows/ci.yml`) using the mswin
|
|
66
|
+
(MSVC) Ruby: it compiles the extension, runs the core test suite, and verifies a
|
|
67
|
+
clean `gem install` against the Ruby headers alone.
|
|
68
|
+
- `extconf.rb` no longer runs `nmake clean`/`make clean` after `create_makefile`
|
|
69
|
+
(it ran during `gem install`, just before the build, so it was pointless noise).
|
|
70
|
+
- README: honest performance framing, a CI badge in place of the static
|
|
71
|
+
"373 Passing"/"High Performance" badges, and corrected test/skip counts (5 skips).
|
|
72
|
+
|
|
73
|
+
## [3.16.15] - 2025-12-20
|
|
74
|
+
|
|
75
|
+
- Published release following 3.16.14. This entry was added retroactively to
|
|
76
|
+
document the version that was actually shipped to RubyGems.
|
|
77
|
+
|
|
5
78
|
## [3.16.14] - 2025-12-20
|
|
6
79
|
|
|
7
80
|
### Initial Release
|
data/README.md
CHANGED
|
@@ -1,164 +1,168 @@
|
|
|
1
|
-
# oj_windows
|
|
2
|
-
|
|
3
|
-
**A Windows-native, high-performance JSON parser and Object marshaller for Ruby.**
|
|
4
|
-
|
|
5
|
-
[](https://rubygems.org/gems/oj_windows)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
gem
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```ruby
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
|
71
|
-
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
|
112
|
-
|
|
113
|
-
| `:
|
|
114
|
-
| `:
|
|
115
|
-
| `:
|
|
116
|
-
| `:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
- [
|
|
138
|
-
- [
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
#
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
1
|
+
# oj_windows
|
|
2
|
+
|
|
3
|
+
**A Windows-native, high-performance JSON parser and Object marshaller for Ruby.**
|
|
4
|
+
|
|
5
|
+
[](https://rubygems.org/gems/oj_windows)
|
|
6
|
+
[](https://www.ruby-lang.org/)
|
|
7
|
+
[](https://github.com/tigel-agm/oj_windows)
|
|
8
|
+
[](https://github.com/tigel-agm/oj_windows/blob/main/LICENSE)
|
|
9
|
+
[](https://github.com/tigel-agm/oj_windows/actions/workflows/ci.yml)
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
`oj_windows` is a fork of [Oj](https://github.com/ohler55/oj) by Peter Ohler, adapted to build with the **MSVC (mswin)** Ruby toolchain. POSIX-specific code has been guarded or replaced with native Windows equivalents (pthread mutexes → Windows synchronization, `timegm` → `_mkgmtime`, guarded POSIX headers), and SIMD string scanning is enabled under MSVC.
|
|
14
|
+
|
|
15
|
+
> **Relationship to upstream Oj.** Almost all of this code is Peter Ohler's. `oj_windows` exists only to provide a buildable Oj for Ruby compiled with the MSVC toolchain. It defines the same `Oj` module and the same public API, so **it is a drop-in replacement for — and cannot be installed alongside — the upstream `oj` gem**. If you use the standard **RubyInstaller / MinGW** Ruby, install the upstream [`oj`](https://rubygems.org/gems/oj) gem instead (it builds there via the MSYS2 devkit); `oj_windows` is only needed for native MSVC (`mswin`) builds.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
| Component | Version |
|
|
20
|
+
|-----------|---------|
|
|
21
|
+
| Ruby | 3.4.8+ (MSVC build) |
|
|
22
|
+
| OS | Windows 10/11 x64 |
|
|
23
|
+
| Compiler | Visual Studio 2022+ |
|
|
24
|
+
| Architecture | x64-mswin64_140 |
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
gem install oj_windows
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or in your Gemfile:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
gem 'oj_windows'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
require 'oj_windows'
|
|
42
|
+
|
|
43
|
+
# Dump Ruby objects to JSON
|
|
44
|
+
hash = { 'name' => 'oj_windows', 'version' => '3.17.2.1', 'windows' => true }
|
|
45
|
+
json = Oj.dump(hash)
|
|
46
|
+
# => {"name":"oj_windows","version":"3.16.14","windows":true}
|
|
47
|
+
|
|
48
|
+
# Load JSON back to Ruby objects
|
|
49
|
+
data = Oj.load(json)
|
|
50
|
+
# => {"name"=>"oj_windows", "version"=>"3.16.14", "windows"=>true}
|
|
51
|
+
|
|
52
|
+
# Pretty print
|
|
53
|
+
puts Oj.dump(hash, indent: 2)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
- **SIMD-accelerated** C extension compiled with MSVC (SSE2 string scanning on x86_64)
|
|
59
|
+
- **Multiple Modes**: Strict, Compat, Object, Custom, Rails, WAB, Null
|
|
60
|
+
- **JSON Gem Compatibility**: Drop-in replacement via `Oj.mimic_JSON`
|
|
61
|
+
- **Rails Integration**: `:rails` mode and `Oj.optimize_rails` for ActiveSupport/ActiveRecord (see note under Test Results)
|
|
62
|
+
- **Streaming**: SAJ and SC parsers for large documents
|
|
63
|
+
- **Safe parsing**: `Oj::Parser.safe(max_depth:, max_array_size:, max_hash_size:, max_total_elements:)` enforces limits on untrusted input
|
|
64
|
+
- **StringWriter/StreamWriter**: Efficient JSON generation
|
|
65
|
+
|
|
66
|
+
## Test Results
|
|
67
|
+
|
|
68
|
+
All tests pass on Windows MSVC Ruby 3.4.8:
|
|
69
|
+
|
|
70
|
+
| Test Suite | Runs | Assertions | Failures | Errors | Skips |
|
|
71
|
+
|------------|------|------------|----------|--------|-------|
|
|
72
|
+
| test_various.rb | 69 | 8,202 | 0 | 0 | 1 |
|
|
73
|
+
| test_strict.rb | 42 | 71 | 0 | 0 | 0 |
|
|
74
|
+
| test_compat.rb | 55 | 112 | 0 | 0 | 0 |
|
|
75
|
+
| test_object.rb | 74 | 161 | 0 | 0 | 0 |
|
|
76
|
+
| test_fast.rb | 43 | 137 | 0 | 0 | 0 |
|
|
77
|
+
| test_saj.rb | 13 | 18 | 0 | 0 | 0 |
|
|
78
|
+
| test_scp.rb | 23 | 23 | 0 | 0 | 2 |
|
|
79
|
+
| test_gc.rb | 3 | 50 | 0 | 0 | 0 |
|
|
80
|
+
| test_writer.rb | 27 | 28 | 0 | 0 | 1 |
|
|
81
|
+
| test_file.rb | 21 | 52 | 0 | 0 | 1 |
|
|
82
|
+
| test_hash.rb | 3 | 7 | 0 | 0 | 0 |
|
|
83
|
+
| **Total** | **373** | **8,861** | **0** | **0** | **5** |
|
|
84
|
+
|
|
85
|
+
> **Scope**: This is the core suite run by `test/test_all_no_rails.bat`. Additional mode/parser tests (`test_custom`, `test_null`, `test_wab`, `test_generate`, `test_parser_usual`, `test_integer_range`, `test_long_strings`) also pass. A few files depend on POSIX fixtures or a specific working directory (`test_realworld` needs `test/data/*.json`; `test_parser_saj`'s file test needs a local fixture) and are not part of this table. The Rails ActiveSupport/ActiveRecord suites require `fork` and are not run on Windows.
|
|
86
|
+
>
|
|
87
|
+
> **Skips (5)**: 3 require `fork` (`test_various` ×1, `test_scp` ×2), 1 needs a POSIX subprocess (`test_writer`), and 1 involves pre-1970 dates the Windows time API does not support (`test_file`).
|
|
88
|
+
|
|
89
|
+
## Performance
|
|
90
|
+
|
|
91
|
+
`oj_windows` enables SIMD-accelerated string scanning on x86_64 (SSE2 by default —
|
|
92
|
+
see [InstallOptions](pages/InstallOptions.md)). On string-heavy payloads this makes
|
|
93
|
+
parsing roughly **20–25% faster** than the scalar build that earlier versions
|
|
94
|
+
shipped on MSVC.
|
|
95
|
+
|
|
96
|
+
A note on honest benchmarking: Ruby's bundled `JSON::Ext` is extremely well
|
|
97
|
+
optimized and is competitive with — and on small, simple payloads can exceed —
|
|
98
|
+
`oj_windows` on raw parse/dump throughput. Oj's value is less about winning a
|
|
99
|
+
micro-benchmark and more about capabilities the JSON gem does not offer:
|
|
100
|
+
|
|
101
|
+
- **Object mode** — full Ruby object serialization/deserialization
|
|
102
|
+
- **Rails / ActiveSupport** integration (`Oj.optimize_rails`)
|
|
103
|
+
- **Streaming** parsers (SAJ, SCP) for large documents
|
|
104
|
+
- **Custom** serialization behavior and circular-reference handling
|
|
105
|
+
|
|
106
|
+
Benchmark your own representative payloads with the scripts in `test/perf_*.rb`
|
|
107
|
+
rather than relying on synthetic numbers.
|
|
108
|
+
|
|
109
|
+
## Modes
|
|
110
|
+
|
|
111
|
+
| Mode | Description |
|
|
112
|
+
|------|-------------|
|
|
113
|
+
| `:strict` | Strict JSON compliance, only native types |
|
|
114
|
+
| `:compat` | Compatible with the JSON gem |
|
|
115
|
+
| `:object` | Full Ruby object serialization |
|
|
116
|
+
| `:custom` | Customizable serialization behavior |
|
|
117
|
+
| `:rails` | Rails and ActiveSupport compatibility |
|
|
118
|
+
| `:wab` | WAB (Web Application Builder) format |
|
|
119
|
+
| `:null` | Return null for unsupported types |
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
# Set default options
|
|
125
|
+
Oj.default_options = {
|
|
126
|
+
mode: :compat,
|
|
127
|
+
symbol_keys: true,
|
|
128
|
+
indent: 2
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Check current options
|
|
132
|
+
Oj.default_options
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Documentation
|
|
136
|
+
|
|
137
|
+
- [Options](pages/Options.md) - Parse and dump options
|
|
138
|
+
- [Modes](pages/Modes.md) - Detailed mode documentation
|
|
139
|
+
- [Rails](pages/Rails.md) - Rails integration guide
|
|
140
|
+
- [JsonGem](pages/JsonGem.md) - JSON gem compatibility
|
|
141
|
+
- [Advanced](pages/Advanced.md) - Advanced features
|
|
142
|
+
|
|
143
|
+
## Building from Source
|
|
144
|
+
|
|
145
|
+
```powershell
|
|
146
|
+
# Requires a Visual Studio (2019+) MSVC build environment. package_install.bat
|
|
147
|
+
# locates vcvars64.bat automatically via vswhere, so just run:
|
|
148
|
+
.\package_install.bat
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
> If you prefer to set up the environment yourself, run the `vcvars64.bat` from
|
|
152
|
+
> your Visual Studio install (e.g. `...\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat`)
|
|
153
|
+
> first, then `bundle exec rake compile`.
|
|
154
|
+
|
|
155
|
+
## Running Tests
|
|
156
|
+
|
|
157
|
+
```powershell
|
|
158
|
+
cd test
|
|
159
|
+
.\test_all_no_rails.bat
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT License - See [LICENSE](LICENSE) for details.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
*Version 3.17.2.1 — based on [Oj](https://github.com/ohler55/oj) 3.17.2 by Peter Ohler (MIT).*
|
data/ext/oj_windows/extconf.rb
CHANGED
|
@@ -52,6 +52,13 @@ if enable_config('trace-log', false)
|
|
|
52
52
|
dflags['OJ_ENABLE_TRACE_LOG'] = 1
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# SIMD string scanning is enabled by default (SSE2/SSE4.2 on x86_64 including
|
|
56
|
+
# MSVC, NEON on ARM). Build with `--disable-simd` to force the portable scalar
|
|
57
|
+
# scanner, e.g. `gem install oj_windows -- --disable-simd`.
|
|
58
|
+
unless enable_config('simd', true)
|
|
59
|
+
dflags['OJ_DISABLE_SIMD'] = 1
|
|
60
|
+
end
|
|
61
|
+
|
|
55
62
|
dflags.each do |k, v|
|
|
56
63
|
if v.nil?
|
|
57
64
|
$CPPFLAGS += " -D#{k}"
|
|
@@ -70,8 +77,7 @@ end
|
|
|
70
77
|
|
|
71
78
|
create_makefile(File.join(extension_name, extension_name))
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
end
|
|
80
|
+
# NOTE: do not run `nmake clean` / `make clean` here. This file runs during
|
|
81
|
+
# `gem install` right before the build step, so cleaning is pointless on a fresh
|
|
82
|
+
# install (there is nothing to clean) and only emits confusing output. Use
|
|
83
|
+
# `rake clean` for local development instead.
|
data/ext/oj_windows/mem.c
CHANGED
|
@@ -31,7 +31,21 @@ typedef struct _rep {
|
|
|
31
31
|
|
|
32
32
|
#ifdef MEM_DEBUG
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
#if IS_WINDOWS
|
|
35
|
+
// Included here (after ruby.h, which already pulls in winsock2/windows on mswin)
|
|
36
|
+
// to avoid the winsock.h vs winsock2.h redefinition clash that occurs if
|
|
37
|
+
// <windows.h> is included ahead of Ruby's headers.
|
|
38
|
+
#include <windows.h>
|
|
39
|
+
// CRITICAL_SECTION has no static initializer, but SRWLOCK does (SRWLOCK_INIT)
|
|
40
|
+
// and is the natural Windows equivalent for this simple debug-only lock.
|
|
41
|
+
static SRWLOCK lock = SRWLOCK_INIT;
|
|
42
|
+
#define MEM_LOCK() AcquireSRWLockExclusive(&lock)
|
|
43
|
+
#define MEM_UNLOCK() ReleaseSRWLockExclusive(&lock)
|
|
44
|
+
#else
|
|
45
|
+
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
|
46
|
+
#define MEM_LOCK() pthread_mutex_lock(&lock)
|
|
47
|
+
#define MEM_UNLOCK() pthread_mutex_unlock(&lock)
|
|
48
|
+
#endif
|
|
35
49
|
static Rec recs = NULL;
|
|
36
50
|
static const char mem_pad[] = "--- This is a memory pad and should not change until being freed. ---";
|
|
37
51
|
|
|
@@ -48,10 +62,10 @@ void *oj_malloc(size_t size, const char *file, int line) {
|
|
|
48
62
|
r->file = file;
|
|
49
63
|
r->line = line;
|
|
50
64
|
r->ruby = false;
|
|
51
|
-
|
|
65
|
+
MEM_LOCK();
|
|
52
66
|
r->next = recs;
|
|
53
67
|
recs = r;
|
|
54
|
-
|
|
68
|
+
MEM_UNLOCK();
|
|
55
69
|
} else {
|
|
56
70
|
free(ptr);
|
|
57
71
|
ptr = NULL;
|
|
@@ -66,7 +80,7 @@ void *oj_realloc(void *orig, size_t size, const char *file, int line) {
|
|
|
66
80
|
|
|
67
81
|
if (NULL != ptr) {
|
|
68
82
|
strcpy(((char *)ptr) + size, mem_pad);
|
|
69
|
-
|
|
83
|
+
MEM_LOCK();
|
|
70
84
|
for (r = recs; NULL != r; r = r->next) {
|
|
71
85
|
if (orig == r->ptr) {
|
|
72
86
|
r->ptr = ptr;
|
|
@@ -77,7 +91,7 @@ void *oj_realloc(void *orig, size_t size, const char *file, int line) {
|
|
|
77
91
|
break;
|
|
78
92
|
}
|
|
79
93
|
}
|
|
80
|
-
|
|
94
|
+
MEM_UNLOCK();
|
|
81
95
|
if (NULL == r) {
|
|
82
96
|
printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
|
|
83
97
|
}
|
|
@@ -100,10 +114,10 @@ void *oj_calloc(size_t count, size_t size, const char *file, int line) {
|
|
|
100
114
|
r->file = file;
|
|
101
115
|
r->line = line;
|
|
102
116
|
r->ruby = false;
|
|
103
|
-
|
|
117
|
+
MEM_LOCK();
|
|
104
118
|
r->next = recs;
|
|
105
119
|
recs = r;
|
|
106
|
-
|
|
120
|
+
MEM_UNLOCK();
|
|
107
121
|
} else {
|
|
108
122
|
free(ptr);
|
|
109
123
|
ptr = NULL;
|
|
@@ -125,10 +139,10 @@ void *oj_r_alloc(size_t size, const char *file, int line) {
|
|
|
125
139
|
r->file = file;
|
|
126
140
|
r->line = line;
|
|
127
141
|
r->ruby = true;
|
|
128
|
-
|
|
142
|
+
MEM_LOCK();
|
|
129
143
|
r->next = recs;
|
|
130
144
|
recs = r;
|
|
131
|
-
|
|
145
|
+
MEM_UNLOCK();
|
|
132
146
|
} else {
|
|
133
147
|
free(ptr);
|
|
134
148
|
ptr = NULL;
|
|
@@ -143,7 +157,7 @@ void *oj_r_realloc(void *orig, size_t size, const char *file, int line) {
|
|
|
143
157
|
|
|
144
158
|
if (NULL != ptr) {
|
|
145
159
|
strcpy(((char *)ptr) + size, mem_pad);
|
|
146
|
-
|
|
160
|
+
MEM_LOCK();
|
|
147
161
|
for (r = recs; NULL != r; r = r->next) {
|
|
148
162
|
if (orig == r->ptr) {
|
|
149
163
|
r->ptr = ptr;
|
|
@@ -154,7 +168,7 @@ void *oj_r_realloc(void *orig, size_t size, const char *file, int line) {
|
|
|
154
168
|
break;
|
|
155
169
|
}
|
|
156
170
|
}
|
|
157
|
-
|
|
171
|
+
MEM_UNLOCK();
|
|
158
172
|
if (NULL == r) {
|
|
159
173
|
printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
|
|
160
174
|
}
|
|
@@ -167,7 +181,7 @@ void oj_freed(void *ptr, const char *file, int line, bool ruby) {
|
|
|
167
181
|
Rec r = NULL;
|
|
168
182
|
Rec prev = NULL;
|
|
169
183
|
|
|
170
|
-
|
|
184
|
+
MEM_LOCK();
|
|
171
185
|
for (r = recs; NULL != r; r = r->next) {
|
|
172
186
|
if (ptr == r->ptr) {
|
|
173
187
|
if (NULL == prev) {
|
|
@@ -179,7 +193,7 @@ void oj_freed(void *ptr, const char *file, int line, bool ruby) {
|
|
|
179
193
|
}
|
|
180
194
|
prev = r;
|
|
181
195
|
}
|
|
182
|
-
|
|
196
|
+
MEM_UNLOCK();
|
|
183
197
|
if (NULL == r) {
|
|
184
198
|
printf("Free at %s:%d (%p) not allocated or already freed.\n", file, line, ptr);
|
|
185
199
|
} else {
|
|
@@ -242,10 +256,10 @@ char *oj_mem_strdup(const char *str, const char *file, int line) {
|
|
|
242
256
|
r->file = file;
|
|
243
257
|
r->line = line;
|
|
244
258
|
r->ruby = false;
|
|
245
|
-
|
|
259
|
+
MEM_LOCK();
|
|
246
260
|
r->next = recs;
|
|
247
261
|
recs = r;
|
|
248
|
-
|
|
262
|
+
MEM_UNLOCK();
|
|
249
263
|
} else {
|
|
250
264
|
free(ptr);
|
|
251
265
|
ptr = NULL;
|
|
@@ -281,7 +295,7 @@ static Rep update_reps(Rep reps, Rec r) {
|
|
|
281
295
|
|
|
282
296
|
static void print_stats() {
|
|
283
297
|
printf("\n--- Memory Usage Report --------------------------------------------------------\n");
|
|
284
|
-
|
|
298
|
+
MEM_LOCK();
|
|
285
299
|
|
|
286
300
|
if (NULL == recs) {
|
|
287
301
|
printf("No memory leaks\n");
|
|
@@ -306,7 +320,7 @@ static void print_stats() {
|
|
|
306
320
|
}
|
|
307
321
|
printf("%lu bytes leaked\n", leaked);
|
|
308
322
|
}
|
|
309
|
-
|
|
323
|
+
MEM_UNLOCK();
|
|
310
324
|
printf("--------------------------------------------------------------------------------\n");
|
|
311
325
|
}
|
|
312
326
|
|
data/ext/oj_windows/oj.h
CHANGED
|
@@ -34,6 +34,12 @@ extern "C" {
|
|
|
34
34
|
#if defined(_MSC_VER)
|
|
35
35
|
#define __attribute__(x)
|
|
36
36
|
#define timegm _mkgmtime
|
|
37
|
+
// MSVC has no native ssize_t (only SSIZE_T from <BaseTsd.h>, pulled in by
|
|
38
|
+
// <windows.h> above). Ruby's mswin headers normally define ssize_t/HAVE_SSIZE_T;
|
|
39
|
+
// provide a fallback only if they did not, so the extension never relies on it.
|
|
40
|
+
#if !defined(HAVE_SSIZE_T) && !defined(ssize_t)
|
|
41
|
+
typedef SSIZE_T ssize_t;
|
|
42
|
+
#endif
|
|
37
43
|
#endif
|
|
38
44
|
#else
|
|
39
45
|
#define IS_WINDOWS 0
|