Skip to content

Commit 42b6533

Browse files
author
Guy Bedford
authored
ci: StarlingMonkey WPT debug build (#896)
1 parent dff436d commit 42b6533

File tree

7 files changed

+217
-27
lines changed

7 files changed

+217
-27
lines changed

.github/workflows/main.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,62 @@ jobs:
485485
timeout-minutes: 20
486486
run: node ./tests/wpt-harness/run-wpt.mjs --starlingmonkey -vv
487487

488+
starlingmonkey-run_wpt-debug:
489+
concurrency:
490+
group: ${{ github.head_ref }}-${{ github.workflow}}-starlingmonkey-run_wpt-debug
491+
cancel-in-progress: true
492+
if: github.ref != 'refs/heads/main'
493+
name: Run Web Platform Tests (starlingmonkey)
494+
needs: [starlingmonkey-build, ensure_cargo_installs]
495+
runs-on: ubuntu-latest
496+
steps:
497+
- uses: actions/checkout@v3
498+
with:
499+
submodules: true
500+
- uses: actions/setup-node@v3
501+
with:
502+
node-version: 20
503+
cache: 'yarn'
504+
505+
- name: Download Engine
506+
uses: actions/download-artifact@v3
507+
with:
508+
name: starling-debug
509+
510+
- name: Restore Viceroy from cache
511+
uses: actions/cache@v3
512+
with:
513+
path: "/home/runner/.cargo/bin/viceroy"
514+
key: crate-cache-viceroy-${{ env.viceroy_version }}
515+
516+
- name: Restore wasm-tools from cache
517+
uses: actions/cache@v3
518+
id: wasm-tools
519+
with:
520+
path: "/home/runner/.cargo/bin/wasm-tools"
521+
key: crate-cache-wasm-tools-${{ env.wasm-tools_version }}
522+
523+
- name: "Check wasm-tools has been restored"
524+
if: steps.wasm-tools.outputs.cache-hit != 'true'
525+
run: |
526+
echo "wasm-tools was not restored from the cache"
527+
echo "bailing out from the build early"
528+
exit 1
529+
530+
- run: yarn install --frozen-lockfile
531+
532+
- name: Build WPT runtime
533+
run: tests/wpt-harness/build-wpt-runtime.sh --debug-build
534+
535+
- name: Prepare WPT hosts
536+
run: |
537+
cd tests/wpt-harness/wpt
538+
./wpt make-hosts-file | sudo tee -a /etc/hosts
539+
540+
- name: Run tests
541+
timeout-minutes: 20
542+
run: node ./tests/wpt-harness/run-wpt.mjs --starlingmonkey -vv
543+
488544
starlingmonkey-run_wpt-weval:
489545
concurrency:
490546
group: ${{ github.head_ref }}-${{ github.workflow}}-starlingmonkey-run_wpt-weval

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"test:cli": "brittle --bail integration-tests/cli/**.test.js",
3535
"test:integration": "node ./integration-tests/js-compute/test.js",
3636
"test:wpt": "tests/wpt-harness/build-wpt-runtime.sh && node ./tests/wpt-harness/run-wpt.mjs -vv",
37+
"test:wpt:debug": "tests/wpt-harness/build-wpt-runtime.sh --debug-build && node ./tests/wpt-harness/run-wpt.mjs --starlingmonkey -vv",
3738
"test:types": "tsd",
3839
"build": "make -j8 -C runtime/js-compute-runtime && cp runtime/js-compute-runtime/js-compute-runtime.wasm .",
3940
"build:debug": "DEBUG=true make -j8 -C runtime/js-compute-runtime && cp runtime/js-compute-runtime/js-compute-runtime.wasm .",

runtime/StarlingMonkey

Submodule StarlingMonkey updated 46 files

runtime/fastly/builtins/fetch/headers.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "./headers.h"
22
#include "../../../StarlingMonkey/runtime/encode.h"
33
#include "../../../StarlingMonkey/runtime/sequence.hpp"
4+
#include "../../common/sequence.hpp"
45
#include "../../host-api/host_api_fastly.h"
56
#include "../fastly.h"
67
#include "./request-response.h"
@@ -144,19 +145,30 @@ host_api::HostString normalize_header_value(JSContext *cx, JS::MutableHandleValu
144145
return nullptr;
145146
}
146147

147-
#pragma clang diagnostic push
148-
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
149-
if (!JS_DeprecatedStringHasLatin1Chars(value_str)) {
150-
#pragma clang diagnostic pop
151-
JS::AutoCheckCannotGC nogc;
152-
size_t length;
153-
const char16_t *chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, value_str, &length);
154-
for (auto i = 0; i < length; i++) {
155-
if (chars[i] > 255) {
156-
JS_ReportErrorASCII(cx, "header value contains bytes greater than 255");
157-
return nullptr;
148+
if (!JS::StringHasLatin1Chars(value_str)) {
149+
bool has_err = false;
150+
// First ensure string is linear and not a rope or atom.
151+
JSLinearString *lstr = JS_EnsureLinearString(cx, value_str);
152+
if (!lstr) {
153+
return nullptr;
154+
}
155+
{
156+
JS::AutoCheckCannotGC nogc;
157+
size_t length;
158+
const char16_t *chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, value_str, &length);
159+
MOZ_ASSERT(chars);
160+
for (auto i = 0; i < length; i++) {
161+
if (chars[i] > 255) {
162+
has_err = true;
163+
break;
164+
}
158165
}
159166
}
167+
// Error must be reported outside of GC guard
168+
if (has_err) {
169+
JS_ReportErrorASCII(cx, "header value contains bytes greater than 255");
170+
return nullptr;
171+
}
160172
}
161173

162174
host_api::HostString value;
@@ -576,8 +588,8 @@ JSObject *Headers::create(JSContext *cx, JS::HandleObject self, Headers::Mode mo
576588
}
577589

578590
bool consumed = false;
579-
if (!core::maybe_consume_sequence_or_record<Headers::append_header_value>(cx, initv, headers,
580-
&consumed, "Headers")) {
591+
if (!common::maybe_consume_sequence_or_record<Headers::append_header_value>(
592+
cx, initv, headers, &consumed, "Headers")) {
581593
return nullptr;
582594
}
583595

runtime/fastly/builtins/fetch/request-response.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -386,23 +386,28 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self,
386386
char *buf;
387387
size_t length;
388388

389+
host_api::Result<host_api::Void> write_res;
390+
391+
host_api::HttpBody body{RequestOrResponse::body_handle(self)};
389392
if (body_obj && JS_IsArrayBufferViewObject(body_obj)) {
390393
// Short typed arrays have inline data which can move on GC, so assert
391394
// that no GC happens. (Which it doesn't, because we're not allocating
392395
// before `buf` goes out of scope.)
393-
maybeNoGC.emplace(cx);
394-
JS::AutoCheckCannotGC &noGC = maybeNoGC.ref();
396+
JS::AutoCheckCannotGC noGC(cx);
395397
bool is_shared;
396398
length = JS_GetArrayBufferViewByteLength(body_obj);
397399
buf = (char *)JS_GetArrayBufferViewData(body_obj, &is_shared, noGC);
400+
write_res = body.write_all_back(reinterpret_cast<uint8_t *>(buf), length);
398401
} else if (body_obj && JS::IsArrayBufferObject(body_obj)) {
399402
bool is_shared;
400403
JS::GetArrayBufferLengthAndData(body_obj, &length, &is_shared, (uint8_t **)&buf);
404+
write_res = body.write_all_back(reinterpret_cast<uint8_t *>(buf), length);
401405
} else if (body_obj && URLSearchParams::is_instance(body_obj)) {
402406
auto slice = URLSearchParams::serialize(cx, body_obj);
403407
buf = (char *)slice.data;
404408
length = slice.len;
405409
content_type = "application/x-www-form-urlencoded;charset=UTF-8";
410+
write_res = body.write_all_back(reinterpret_cast<uint8_t *>(buf), length);
406411
} else {
407412
{
408413
auto str = core::encode(cx, body_val);
@@ -415,15 +420,7 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self,
415420
}
416421
buf = text.get();
417422
content_type = "text/plain;charset=UTF-8";
418-
}
419-
420-
host_api::HttpBody body{RequestOrResponse::body_handle(self)};
421-
auto write_res = body.write_all_back(reinterpret_cast<uint8_t *>(buf), length);
422-
423-
// Ensure that the NoGC is reset, so throwing an error in HANDLE_ERROR
424-
// succeeds.
425-
if (maybeNoGC.isSome()) {
426-
maybeNoGC.reset();
423+
write_res = body.write_all_back(reinterpret_cast<uint8_t *>(buf), length);
427424
}
428425

429426
if (auto *err = write_res.to_err()) {

runtime/fastly/common/sequence.hpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#ifndef FASTLY_SEQUENCE_HPP
2+
#define FASTLY_SEQUENCE_HPP
3+
4+
// TODO: remove these once the warnings are fixed
5+
#pragma clang diagnostic push
6+
#pragma clang diagnostic ignored "-Winvalid-offsetof"
7+
#include "jsapi.h"
8+
#include "jsfriendapi.h"
9+
#include "js/ForOfIterator.h"
10+
#pragma clang diagnostic pop
11+
12+
namespace fastly::common {
13+
14+
inline bool report_sequence_or_record_arg_error(JSContext *cx, const char *name,
15+
const char *alt_text) {
16+
JS_ReportErrorUTF8(cx,
17+
"Failed to construct %s object. If defined, the first "
18+
"argument must be either a [ ['name', 'value'], ... ] sequence, "
19+
"or a { 'name' : 'value', ... } record%s.",
20+
name, alt_text);
21+
return false;
22+
}
23+
24+
/**
25+
* Extract <key,value> pairs from the given value if it is either a
26+
* sequence<sequence<Value> or a record<Value, Value>.
27+
*/
28+
template <auto apply>
29+
bool maybe_consume_sequence_or_record(JSContext *cx, JS::HandleValue initv, JS::HandleObject target,
30+
bool *consumed, const char *ctor_name,
31+
const char *alt_text = "") {
32+
if (initv.isUndefined()) {
33+
*consumed = true;
34+
return true;
35+
}
36+
37+
JS::RootedValue key(cx);
38+
JS::RootedValue value(cx);
39+
40+
// First, try consuming args[0] as a sequence<sequence<Value>>.
41+
JS::ForOfIterator it(cx);
42+
if (!it.init(initv, JS::ForOfIterator::AllowNonIterable))
43+
return false;
44+
45+
// Note: this currently doesn't treat strings as iterable even though they
46+
// are. We don't have any constructors that want to iterate over strings, and
47+
// this makes things a lot easier.
48+
if (initv.isObject() && it.valueIsIterable()) {
49+
JS::RootedValue entry(cx);
50+
51+
while (true) {
52+
bool done;
53+
if (!it.next(&entry, &done))
54+
return false;
55+
56+
if (done)
57+
break;
58+
59+
if (!entry.isObject())
60+
return report_sequence_or_record_arg_error(cx, ctor_name, alt_text);
61+
62+
JS::ForOfIterator entr_iter(cx);
63+
if (!entr_iter.init(entry, JS::ForOfIterator::AllowNonIterable))
64+
return false;
65+
66+
if (!entr_iter.valueIsIterable())
67+
return report_sequence_or_record_arg_error(cx, ctor_name, alt_text);
68+
69+
{
70+
bool done;
71+
72+
// Extract key.
73+
if (!entr_iter.next(&key, &done))
74+
return false;
75+
if (done)
76+
return report_sequence_or_record_arg_error(cx, ctor_name, alt_text);
77+
78+
// Extract value.
79+
if (!entr_iter.next(&value, &done))
80+
return false;
81+
if (done)
82+
return report_sequence_or_record_arg_error(cx, ctor_name, alt_text);
83+
84+
// Ensure that there aren't any further entries.
85+
if (!entr_iter.next(&entry, &done))
86+
return false;
87+
if (!done)
88+
return report_sequence_or_record_arg_error(cx, ctor_name, alt_text);
89+
90+
if (!apply(cx, target, key, value, ctor_name))
91+
return false;
92+
}
93+
}
94+
*consumed = true;
95+
} else if (initv.isObject()) {
96+
// init isn't an iterator, so if it's an object, it must be a record to be
97+
// valid input.
98+
JS::RootedObject init(cx, &initv.toObject());
99+
JS::RootedIdVector ids(cx);
100+
if (!js::GetPropertyKeys(cx, init, JSITER_OWNONLY | JSITER_SYMBOLS, &ids))
101+
return false;
102+
103+
JS::RootedId curId(cx);
104+
for (size_t i = 0; i < ids.length(); ++i) {
105+
curId = ids[i];
106+
key = js::IdToValue(curId);
107+
108+
if (!JS_GetPropertyById(cx, init, curId, &value))
109+
return false;
110+
111+
if (!apply(cx, target, key, value, ctor_name))
112+
return false;
113+
}
114+
*consumed = true;
115+
} else {
116+
*consumed = false;
117+
}
118+
119+
return true;
120+
}
121+
122+
}
123+
124+
#endif

tests/wpt-harness/expectations-sm/fetch/api/headers/headers-errors.any.js.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"Create headers giving an array having one string as init argument": {
3-
"status": "PASS"
3+
"status": "FAIL"
44
},
55
"Create headers giving an array having three strings as init argument": {
6-
"status": "PASS"
6+
"status": "FAIL"
77
},
88
"Create headers giving bad header name as init argument": {
99
"status": "FAIL"

0 commit comments

Comments
 (0)