1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /* Operations used to implement multiple Intl.* classes. */
8
9 #include "builtin/intl/CommonFunctions.h"
10
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Casting.h"
13 #include "mozilla/intl/ICU4CGlue.h"
14 #include "mozilla/TextUtils.h"
15
16 #include <algorithm>
17
18 #include "gc/GCEnum.h"
19 #include "gc/Zone.h"
20 #include "gc/ZoneAllocator.h"
21 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_INTERNAL_INTL_ERROR
22 #include "js/Value.h"
23 #include "vm/JSContext.h"
24 #include "vm/JSObject.h"
25 #include "vm/SelfHosting.h"
26 #include "vm/Stack.h"
27
28 #include "vm/JSObject-inl.h"
29
InitializeObject(JSContext * cx,JS::Handle<JSObject * > obj,JS::Handle<PropertyName * > initializer,JS::Handle<JS::Value> locales,JS::Handle<JS::Value> options)30 bool js::intl::InitializeObject(JSContext* cx, JS::Handle<JSObject*> obj,
31 JS::Handle<PropertyName*> initializer,
32 JS::Handle<JS::Value> locales,
33 JS::Handle<JS::Value> options) {
34 FixedInvokeArgs<3> args(cx);
35
36 args[0].setObject(*obj);
37 args[1].set(locales);
38 args[2].set(options);
39
40 RootedValue ignored(cx);
41 if (!CallSelfHostedFunction(cx, initializer, JS::NullHandleValue, args,
42 &ignored)) {
43 return false;
44 }
45
46 MOZ_ASSERT(ignored.isUndefined(),
47 "Unexpected return value from non-legacy Intl object initializer");
48 return true;
49 }
50
LegacyInitializeObject(JSContext * cx,JS::Handle<JSObject * > obj,JS::Handle<PropertyName * > initializer,JS::Handle<JS::Value> thisValue,JS::Handle<JS::Value> locales,JS::Handle<JS::Value> options,DateTimeFormatOptions dtfOptions,JS::MutableHandle<JS::Value> result)51 bool js::intl::LegacyInitializeObject(JSContext* cx, JS::Handle<JSObject*> obj,
52 JS::Handle<PropertyName*> initializer,
53 JS::Handle<JS::Value> thisValue,
54 JS::Handle<JS::Value> locales,
55 JS::Handle<JS::Value> options,
56 DateTimeFormatOptions dtfOptions,
57 JS::MutableHandle<JS::Value> result) {
58 FixedInvokeArgs<5> args(cx);
59
60 args[0].setObject(*obj);
61 args[1].set(thisValue);
62 args[2].set(locales);
63 args[3].set(options);
64 args[4].setBoolean(dtfOptions == DateTimeFormatOptions::EnableMozExtensions);
65
66 if (!CallSelfHostedFunction(cx, initializer, NullHandleValue, args, result)) {
67 return false;
68 }
69
70 MOZ_ASSERT(result.isObject(),
71 "Legacy Intl object initializer must return an object");
72 return true;
73 }
74
GetInternalsObject(JSContext * cx,JS::Handle<JSObject * > obj)75 JSObject* js::intl::GetInternalsObject(JSContext* cx,
76 JS::Handle<JSObject*> obj) {
77 FixedInvokeArgs<1> args(cx);
78
79 args[0].setObject(*obj);
80
81 RootedValue v(cx);
82 if (!js::CallSelfHostedFunction(cx, cx->names().getInternals, NullHandleValue,
83 args, &v)) {
84 return nullptr;
85 }
86
87 return &v.toObject();
88 }
89
ReportInternalError(JSContext * cx)90 void js::intl::ReportInternalError(JSContext* cx) {
91 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
92 JSMSG_INTERNAL_INTL_ERROR);
93 }
94
ReportInternalError(JSContext * cx,mozilla::intl::ICUError error)95 void js::intl::ReportInternalError(JSContext* cx,
96 mozilla::intl::ICUError error) {
97 switch (error) {
98 case mozilla::intl::ICUError::OutOfMemory:
99 ReportOutOfMemory(cx);
100 return;
101 case mozilla::intl::ICUError::InternalError:
102 ReportInternalError(cx);
103 return;
104 case mozilla::intl::ICUError::OverflowError:
105 ReportAllocationOverflow(cx);
106 return;
107 }
108 MOZ_CRASH("Unexpected ICU error");
109 }
110
111 const js::intl::OldStyleLanguageTagMapping
112 js::intl::oldStyleLanguageTagMappings[] = {
113 {"pa-PK", "pa-Arab-PK"}, {"zh-CN", "zh-Hans-CN"},
114 {"zh-HK", "zh-Hant-HK"}, {"zh-SG", "zh-Hans-SG"},
115 {"zh-TW", "zh-Hant-TW"},
116 };
117
EncodeLocale(JSContext * cx,JSString * locale)118 js::UniqueChars js::intl::EncodeLocale(JSContext* cx, JSString* locale) {
119 MOZ_ASSERT(locale->length() > 0);
120
121 js::UniqueChars chars = EncodeAscii(cx, locale);
122
123 #ifdef DEBUG
124 // Ensure the returned value contains only valid BCP 47 characters.
125 // (Lambdas can't be placed inside MOZ_ASSERT, so move the checks in an
126 // #ifdef block.)
127 if (chars) {
128 auto alnumOrDash = [](char c) {
129 return mozilla::IsAsciiAlphanumeric(c) || c == '-';
130 };
131 MOZ_ASSERT(mozilla::IsAsciiAlpha(chars[0]));
132 MOZ_ASSERT(
133 std::all_of(chars.get(), chars.get() + locale->length(), alnumOrDash));
134 }
135 #endif
136
137 return chars;
138 }
139
AddICUCellMemory(JSObject * obj,size_t nbytes)140 void js::intl::AddICUCellMemory(JSObject* obj, size_t nbytes) {
141 // Account the (estimated) number of bytes allocated by an ICU object against
142 // the JSObject's zone.
143 AddCellMemory(obj, nbytes, MemoryUse::ICUObject);
144 }
145
RemoveICUCellMemory(JSFreeOp * fop,JSObject * obj,size_t nbytes)146 void js::intl::RemoveICUCellMemory(JSFreeOp* fop, JSObject* obj,
147 size_t nbytes) {
148 fop->removeCellMemory(obj, nbytes, MemoryUse::ICUObject);
149 }
150