Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 29b43ff99fc929d4a0c1ca8bbb13470b467d2a82..df31e70d5c0fcfdefe87e0226717818e8d9ba756 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -66,6 +66,15 @@ |
#include "v8threads.h" |
#include "vm-state-inl.h" |
+#ifdef V8_I18N_SUPPORT |
+#include "unicode/brkiter.h" |
+#include "unicode/coll.h" |
+#include "unicode/datefmt.h" |
+#include "unicode/numfmt.h" |
+#include "unicode/uloc.h" |
+#include "unicode/uversion.h" |
+#endif |
+ |
#ifndef _STLP_VENDOR_CSTD |
// STLPort doesn't import fpclassify and isless into the std namespace. |
using std::fpclassify; |
@@ -712,13 +721,18 @@ void Runtime::SetupArrayBuffer(Isolate* isolate, |
bool Runtime::SetupArrayBufferAllocatingData( |
Isolate* isolate, |
Handle<JSArrayBuffer> array_buffer, |
- size_t allocated_length) { |
+ size_t allocated_length, |
+ bool initialize) { |
void* data; |
CHECK(V8::ArrayBufferAllocator() != NULL); |
if (allocated_length != 0) { |
- data = V8::ArrayBufferAllocator()->Allocate(allocated_length); |
+ if (initialize) { |
+ data = V8::ArrayBufferAllocator()->Allocate(allocated_length); |
+ } else { |
+ data = |
+ V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); |
+ } |
if (data == NULL) return false; |
- memset(data, 0, allocated_length); |
} else { |
data = NULL; |
} |
@@ -805,65 +819,69 @@ enum TypedArrayId { |
ARRAY_ID_UINT8C = 9 |
}; |
- |
-RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { |
- HandleScope scope(isolate); |
- ASSERT(args.length() == 5); |
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); |
- CONVERT_SMI_ARG_CHECKED(arrayId, 1); |
- CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2); |
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3); |
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4); |
- |
- ASSERT(holder->GetInternalFieldCount() == |
- v8::ArrayBufferView::kInternalFieldCount); |
- for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { |
- holder->SetInternalField(i, Smi::FromInt(0)); |
- } |
- |
- ExternalArrayType arrayType; |
- size_t elementSize; |
+static void ArrayIdToTypeAndSize( |
+ int arrayId, ExternalArrayType* array_type, size_t* element_size) { |
switch (arrayId) { |
case ARRAY_ID_UINT8: |
- arrayType = kExternalUnsignedByteArray; |
- elementSize = 1; |
+ *array_type = kExternalUnsignedByteArray; |
+ *element_size = 1; |
break; |
case ARRAY_ID_INT8: |
- arrayType = kExternalByteArray; |
- elementSize = 1; |
+ *array_type = kExternalByteArray; |
+ *element_size = 1; |
break; |
case ARRAY_ID_UINT16: |
- arrayType = kExternalUnsignedShortArray; |
- elementSize = 2; |
+ *array_type = kExternalUnsignedShortArray; |
+ *element_size = 2; |
break; |
case ARRAY_ID_INT16: |
- arrayType = kExternalShortArray; |
- elementSize = 2; |
+ *array_type = kExternalShortArray; |
+ *element_size = 2; |
break; |
case ARRAY_ID_UINT32: |
- arrayType = kExternalUnsignedIntArray; |
- elementSize = 4; |
+ *array_type = kExternalUnsignedIntArray; |
+ *element_size = 4; |
break; |
case ARRAY_ID_INT32: |
- arrayType = kExternalIntArray; |
- elementSize = 4; |
+ *array_type = kExternalIntArray; |
+ *element_size = 4; |
break; |
case ARRAY_ID_FLOAT32: |
- arrayType = kExternalFloatArray; |
- elementSize = 4; |
+ *array_type = kExternalFloatArray; |
+ *element_size = 4; |
break; |
case ARRAY_ID_FLOAT64: |
- arrayType = kExternalDoubleArray; |
- elementSize = 8; |
+ *array_type = kExternalDoubleArray; |
+ *element_size = 8; |
break; |
case ARRAY_ID_UINT8C: |
- arrayType = kExternalPixelArray; |
- elementSize = 1; |
+ *array_type = kExternalPixelArray; |
+ *element_size = 1; |
break; |
default: |
UNREACHABLE(); |
- return NULL; |
} |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 5); |
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); |
+ CONVERT_SMI_ARG_CHECKED(arrayId, 1); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4); |
+ |
+ ASSERT(holder->GetInternalFieldCount() == |
+ v8::ArrayBufferView::kInternalFieldCount); |
+ for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { |
+ holder->SetInternalField(i, Smi::FromInt(0)); |
+ } |
+ |
+ ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. |
+ size_t element_size = 1; // Bogus initialization. |
+ ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); |
holder->set_buffer(*buffer); |
holder->set_byte_offset(*byte_offset_object); |
@@ -871,8 +889,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { |
size_t byte_offset = NumberToSize(isolate, *byte_offset_object); |
size_t byte_length = NumberToSize(isolate, *byte_length_object); |
- ASSERT(byte_length % elementSize == 0); |
- size_t length = byte_length / elementSize; |
+ ASSERT(byte_length % element_size == 0); |
+ size_t length = byte_length / element_size; |
Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length); |
holder->set_length(*length_obj); |
@@ -881,13 +899,99 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { |
Handle<ExternalArray> elements = |
isolate->factory()->NewExternalArray( |
- static_cast<int>(length), arrayType, |
+ static_cast<int>(length), array_type, |
static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); |
holder->set_elements(*elements); |
return isolate->heap()->undefined_value(); |
} |
+// Initializes a typed array from an array-like object. |
+// If an array-like object happens to be a typed array of the same type, |
+// initializes backing store using memove. |
+// |
+// Returns true if backing store was initialized or false otherwise. |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 4); |
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); |
+ CONVERT_SMI_ARG_CHECKED(arrayId, 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3); |
+ |
+ ASSERT(holder->GetInternalFieldCount() == |
+ v8::ArrayBufferView::kInternalFieldCount); |
+ for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { |
+ holder->SetInternalField(i, Smi::FromInt(0)); |
+ } |
+ |
+ ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. |
+ size_t element_size = 1; // Bogus initialization. |
+ ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); |
+ |
+ Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); |
+ size_t length = NumberToSize(isolate, *length_obj); |
+ size_t byte_length = length * element_size; |
+ if (byte_length < length) { // Overflow |
+ return isolate->Throw(*isolate->factory()-> |
+ NewRangeError("invalid_array_buffer_length", |
+ HandleVector<Object>(NULL, 0))); |
+ } |
+ |
+ // We assume that the caller of this function will initialize holder |
+ // with the loop |
+ // for(i = 0; i < length; i++) { holder[i] = source[i]; } |
+ // If source is a typed array, this loop will always run to completion, |
+ // so we are sure that the backing store will be initialized. |
+ // Otherwise, we do not know (the indexing operation might throw). |
+ // Hence we require zero initialization unless our source is a typed array. |
+ bool should_zero_initialize = !source->IsJSTypedArray(); |
+ |
+ if (!Runtime::SetupArrayBufferAllocatingData( |
+ isolate, buffer, byte_length, should_zero_initialize)) { |
+ return isolate->Throw(*isolate->factory()-> |
+ NewRangeError("invalid_array_buffer_length", |
+ HandleVector<Object>(NULL, 0))); |
+ } |
+ |
+ holder->set_buffer(*buffer); |
+ holder->set_byte_offset(Smi::FromInt(0)); |
+ Handle<Object> byte_length_obj( |
+ isolate->factory()->NewNumberFromSize(byte_length)); |
+ holder->set_byte_length(*byte_length_obj); |
+ holder->set_length(*length_obj); |
+ holder->set_weak_next(buffer->weak_first_view()); |
+ buffer->set_weak_first_view(*holder); |
+ |
+ Handle<ExternalArray> elements = |
+ isolate->factory()->NewExternalArray( |
+ static_cast<int>(length), array_type, |
+ static_cast<uint8_t*>(buffer->backing_store())); |
+ holder->set_elements(*elements); |
+ |
+ if (source->IsJSTypedArray()) { |
+ Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source)); |
+ |
+ if (typed_array->type() == holder->type()) { |
+ uint8_t* backing_store = |
+ static_cast<uint8_t*>( |
+ JSArrayBuffer::cast(typed_array->buffer())->backing_store()); |
+ size_t source_byte_offset = |
+ NumberToSize(isolate, typed_array->byte_offset()); |
+ OS::MemCopy( |
+ buffer->backing_store(), |
+ backing_store + source_byte_offset, |
+ byte_length); |
+ return *isolate->factory()->true_value(); |
+ } else { |
+ return *isolate->factory()->false_value(); |
+ } |
+ } |
+ |
+ return *isolate->factory()->false_value(); |
+} |
+ |
+ |
#define TYPED_ARRAY_GETTER(getter, accessor) \ |
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \ |
HandleScope scope(isolate); \ |
@@ -907,6 +1011,21 @@ TYPED_ARRAY_GETTER(Length, length) |
#undef TYPED_ARRAY_GETTER |
+// Return codes for Runtime_TypedArraySetFastCases. |
+// Should be synchronized with typedarray.js natives. |
+enum TypedArraySetResultCodes { |
+ // Set from typed array of the same type. |
+ // This is processed by TypedArraySetFastCases |
+ TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0, |
+ // Set from typed array of the different type, overlapping in memory. |
+ TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1, |
+ // Set from typed array of the different type, non-overlapping. |
+ TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2, |
+ // Set from non-typed array. |
+ TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3 |
+}; |
+ |
+ |
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { |
HandleScope scope(isolate); |
CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0); |
@@ -918,7 +1037,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { |
"not_typed_array", HandleVector<Object>(NULL, 0))); |
if (!source_obj->IsJSTypedArray()) |
- return isolate->heap()->false_value(); |
+ return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); |
Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj)); |
Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj)); |
@@ -933,20 +1052,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { |
return isolate->Throw(*isolate->factory()->NewRangeError( |
"typed_array_set_source_too_large", HandleVector<Object>(NULL, 0))); |
- Handle<JSArrayBuffer> target_buffer(JSArrayBuffer::cast(target->buffer())); |
- Handle<JSArrayBuffer> source_buffer(JSArrayBuffer::cast(source->buffer())); |
size_t target_offset = NumberToSize(isolate, target->byte_offset()); |
size_t source_offset = NumberToSize(isolate, source->byte_offset()); |
uint8_t* target_base = |
- static_cast<uint8_t*>(target_buffer->backing_store()) + target_offset; |
+ static_cast<uint8_t*>( |
+ JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset; |
uint8_t* source_base = |
- static_cast<uint8_t*>(source_buffer->backing_store()) + source_offset; |
+ static_cast<uint8_t*>( |
+ JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset; |
// Typed arrays of the same type: use memmove. |
if (target->type() == source->type()) { |
memmove(target_base + offset * target->element_size(), |
source_base, source_byte_length); |
- return isolate->heap()->true_value(); |
+ return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE); |
} |
// Typed arrays of different types over the same backing store |
@@ -954,78 +1073,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { |
source_base + source_byte_length > target_base) || |
(target_base <= source_base && |
target_base + target_byte_length > source_base)) { |
- size_t target_element_size = target->element_size(); |
- size_t source_element_size = source->element_size(); |
- |
- size_t source_length = NumberToSize(isolate, source->length()); |
- |
- // Copy left part |
- size_t left_index; |
- { |
- // First un-mutated byte after the next write |
- uint8_t* target_ptr = target_base + (offset + 1) * target_element_size; |
- // Next read at source_ptr. We do not care for memory changing before |
- // source_ptr - we have already copied it. |
- uint8_t* source_ptr = source_base; |
- for (left_index = 0; |
- left_index < source_length && target_ptr <= source_ptr; |
- left_index++) { |
- Handle<Object> v = Object::GetElement( |
- source, static_cast<uint32_t>(left_index)); |
- JSObject::SetElement( |
- target, static_cast<uint32_t>(offset + left_index), v, |
- NONE, kNonStrictMode); |
- target_ptr += target_element_size; |
- source_ptr += source_element_size; |
- } |
- } |
- // Copy right part |
- size_t right_index; |
- { |
- // First unmutated byte before the next write |
- uint8_t* target_ptr = |
- target_base + (offset + source_length - 1) * target_element_size; |
- // Next read before source_ptr. We do not care for memory changing after |
- // source_ptr - we have already copied it. |
- uint8_t* source_ptr = |
- source_base + source_length * source_element_size; |
- for (right_index = source_length - 1; |
- right_index >= left_index && target_ptr >= source_ptr; |
- right_index--) { |
- Handle<Object> v = Object::GetElement( |
- source, static_cast<uint32_t>(right_index)); |
- JSObject::SetElement( |
- target, static_cast<uint32_t>(offset + right_index), v, |
- NONE, kNonStrictMode); |
- target_ptr -= target_element_size; |
- source_ptr -= source_element_size; |
- } |
- } |
- // There can be at most 8 entries left in the middle that need buffering |
- // (because the largest element_size is 8 times the smallest). |
- ASSERT((right_index + 1) - left_index <= 8); |
- Handle<Object> temp[8]; |
- size_t idx; |
- for (idx = left_index; idx <= right_index; idx++) { |
- temp[idx - left_index] = Object::GetElement( |
- source, static_cast<uint32_t>(idx)); |
- } |
- for (idx = left_index; idx <= right_index; idx++) { |
- JSObject::SetElement( |
- target, static_cast<uint32_t>(offset + idx), temp[idx-left_index], |
- NONE, kNonStrictMode); |
- } |
+ // We do not support overlapping ArrayBuffers |
+ ASSERT( |
+ JSArrayBuffer::cast(target->buffer())->backing_store() == |
+ JSArrayBuffer::cast(source->buffer())->backing_store()); |
+ return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); |
} else { // Non-overlapping typed arrays |
- for (size_t idx = 0; idx < source_length; idx++) { |
- Handle<Object> value = Object::GetElement( |
- source, static_cast<uint32_t>(idx)); |
- JSObject::SetElement( |
- target, static_cast<uint32_t>(offset + idx), value, |
- NONE, kNonStrictMode); |
- } |
+ return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); |
} |
- |
- return isolate->heap()->true_value(); |
} |
@@ -2948,7 +3003,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { |
JavaScriptFrame* frame = stack_iterator.frame(); |
ASSERT_EQ(frame->function(), generator_object->function()); |
- ASSERT(frame->function()->is_compiled()); |
STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); |
STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); |
@@ -8432,7 +8486,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { |
} |
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); |
if (FLAG_parallel_recompilation && sync_with_compiler_thread) { |
- while (function->IsInRecompileQueue() || |
+ while (function->IsMarkedForParallelRecompilation() || |
+ function->IsInRecompileQueue() || |
function->IsMarkedForInstallingRecompiledCode()) { |
isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); |
OS::Sleep(50); |
@@ -12887,7 +12942,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) { |
RUNTIME_ASSERT(script_wrapper->value()->IsScript()); |
Handle<Script> script(Script::cast(script_wrapper->value())); |
- int compilation_state = Smi::cast(script->compilation_state())->value(); |
+ int compilation_state = script->compilation_state(); |
RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); |
script->set_source(*source); |
@@ -13316,6 +13371,200 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { |
#endif // ENABLE_DEBUGGER_SUPPORT |
+#ifdef V8_I18N_SUPPORT |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) { |
+ HandleScope scope(isolate); |
+ |
+ ASSERT(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0); |
+ |
+ v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str)); |
+ |
+ // Return value which denotes invalid language tag. |
+ const char* const kInvalidTag = "invalid-tag"; |
+ |
+ UErrorCode error = U_ZERO_ERROR; |
+ char icu_result[ULOC_FULLNAME_CAPACITY]; |
+ int icu_length = 0; |
+ |
+ uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, |
+ &icu_length, &error); |
+ if (U_FAILURE(error) || icu_length == 0) { |
+ return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); |
+ } |
+ |
+ char result[ULOC_FULLNAME_CAPACITY]; |
+ |
+ // Force strict BCP47 rules. |
+ uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); |
+ |
+ if (U_FAILURE(error)) { |
+ return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); |
+ } |
+ |
+ return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { |
+ HandleScope scope(isolate); |
+ |
+ ASSERT(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(String, service, 0); |
+ |
+ const icu::Locale* available_locales = NULL; |
+ int32_t count = 0; |
+ |
+ if (service->IsUtf8EqualTo(CStrVector("collator"))) { |
+ available_locales = icu::Collator::getAvailableLocales(count); |
+ } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) { |
+ available_locales = icu::NumberFormat::getAvailableLocales(count); |
+ } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) { |
+ available_locales = icu::DateFormat::getAvailableLocales(count); |
+ } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) { |
+ available_locales = icu::BreakIterator::getAvailableLocales(count); |
+ } |
+ |
+ UErrorCode error = U_ZERO_ERROR; |
+ char result[ULOC_FULLNAME_CAPACITY]; |
+ Handle<JSObject> locales = |
+ isolate->factory()->NewJSObject(isolate->object_function()); |
+ |
+ for (int32_t i = 0; i < count; ++i) { |
+ const char* icu_name = available_locales[i].getName(); |
+ |
+ error = U_ZERO_ERROR; |
+ // No need to force strict BCP47 rules. |
+ uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error); |
+ if (U_FAILURE(error)) { |
+ // This shouldn't happen, but lets not break the user. |
+ continue; |
+ } |
+ |
+ RETURN_IF_EMPTY_HANDLE(isolate, |
+ JSObject::SetLocalPropertyIgnoreAttributes( |
+ locales, |
+ isolate->factory()->NewStringFromAscii(CStrVector(result)), |
+ isolate->factory()->NewNumber(i), |
+ NONE)); |
+ } |
+ |
+ return *locales; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) { |
+ SealHandleScope shs(isolate); |
+ |
+ ASSERT(args.length() == 0); |
+ |
+ icu::Locale default_locale; |
+ |
+ // Set the locale |
+ char result[ULOC_FULLNAME_CAPACITY]; |
+ UErrorCode status = U_ZERO_ERROR; |
+ uloc_toLanguageTag( |
+ default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); |
+ if (U_SUCCESS(status)) { |
+ return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); |
+ } |
+ |
+ return isolate->heap()->AllocateStringFromOneByte(CStrVector("und")); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) { |
+ HandleScope scope(isolate); |
+ |
+ ASSERT(args.length() == 1); |
+ |
+ CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0); |
+ |
+ uint32_t length = static_cast<uint32_t>(input->length()->Number()); |
+ Handle<FixedArray> output = isolate->factory()->NewFixedArray(length); |
+ Handle<Name> maximized = |
+ isolate->factory()->NewStringFromAscii(CStrVector("maximized")); |
+ Handle<Name> base = |
+ isolate->factory()->NewStringFromAscii(CStrVector("base")); |
+ for (unsigned int i = 0; i < length; ++i) { |
+ MaybeObject* maybe_string = input->GetElement(i); |
+ Object* locale_id; |
+ if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) { |
+ return isolate->Throw(isolate->heap()->illegal_argument_string()); |
+ } |
+ |
+ v8::String::Utf8Value utf8_locale_id( |
+ v8::Utils::ToLocal(Handle<String>(String::cast(locale_id)))); |
+ |
+ UErrorCode error = U_ZERO_ERROR; |
+ |
+ // Convert from BCP47 to ICU format. |
+ // de-DE-u-co-phonebk -> de_DE@collation=phonebook |
+ char icu_locale[ULOC_FULLNAME_CAPACITY]; |
+ int icu_locale_length = 0; |
+ uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, |
+ &icu_locale_length, &error); |
+ if (U_FAILURE(error) || icu_locale_length == 0) { |
+ return isolate->Throw(isolate->heap()->illegal_argument_string()); |
+ } |
+ |
+ // Maximize the locale. |
+ // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook |
+ char icu_max_locale[ULOC_FULLNAME_CAPACITY]; |
+ uloc_addLikelySubtags( |
+ icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error); |
+ |
+ // Remove extensions from maximized locale. |
+ // de_Latn_DE@collation=phonebook -> de_Latn_DE |
+ char icu_base_max_locale[ULOC_FULLNAME_CAPACITY]; |
+ uloc_getBaseName( |
+ icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error); |
+ |
+ // Get original name without extensions. |
+ // de_DE@collation=phonebook -> de_DE |
+ char icu_base_locale[ULOC_FULLNAME_CAPACITY]; |
+ uloc_getBaseName( |
+ icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error); |
+ |
+ // Convert from ICU locale format to BCP47 format. |
+ // de_Latn_DE -> de-Latn-DE |
+ char base_max_locale[ULOC_FULLNAME_CAPACITY]; |
+ uloc_toLanguageTag(icu_base_max_locale, base_max_locale, |
+ ULOC_FULLNAME_CAPACITY, FALSE, &error); |
+ |
+ // de_DE -> de-DE |
+ char base_locale[ULOC_FULLNAME_CAPACITY]; |
+ uloc_toLanguageTag( |
+ icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); |
+ |
+ if (U_FAILURE(error)) { |
+ return isolate->Throw(isolate->heap()->illegal_argument_string()); |
+ } |
+ |
+ Handle<JSObject> result = |
+ isolate->factory()->NewJSObject(isolate->object_function()); |
+ RETURN_IF_EMPTY_HANDLE(isolate, |
+ JSObject::SetLocalPropertyIgnoreAttributes( |
+ result, |
+ maximized, |
+ isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)), |
+ NONE)); |
+ RETURN_IF_EMPTY_HANDLE(isolate, |
+ JSObject::SetLocalPropertyIgnoreAttributes( |
+ result, |
+ base, |
+ isolate->factory()->NewStringFromAscii(CStrVector(base_locale)), |
+ NONE)); |
+ output->set(i, *result); |
+ } |
+ |
+ Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output); |
+ result->set_length(Smi::FromInt(length)); |
+ return *result; |
+} |
+#endif // V8_I18N_SUPPORT |
+ |
+ |
// Finds the script object from the script data. NOTE: This operation uses |
// heap traversal to find the function generated for the source position |
// for the requested break point. For lazily compiled functions several heap |