blob: 6b78f895862c090dea7088fad9c764a0146091c7 [file] [log] [blame]
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/symbols.h"
namespace dart {
DEFINE_NATIVE_ENTRY(StringBase_createFromCodePoints, 1) {
GET_NATIVE_ARGUMENT(Array, a, arguments->At(0));
// TODO(srdjan): Check that parameterized type is an int.
StackZone* zone = isolate->current_zone();
intptr_t len = a.Length();
// Unbox the array and determine the maximum element width.
bool is_one_byte_string = true;
bool is_two_byte_string = true;
uint32_t* temp = zone->Alloc<uint32_t>(len);
Object& index_object = Object::Handle(isolate);
for (intptr_t i = 0; i < len; i++) {
index_object = a.At(i);
if (!index_object.IsSmi()) {
GrowableArray<const Object*> args;
args.Add(&index_object);
Exceptions::ThrowByType(Exceptions::kArgument, args);
}
intptr_t value = Smi::Cast(index_object).Value();
if (value < 0) {
GrowableArray<const Object*> args;
Exceptions::ThrowByType(Exceptions::kArgument, args);
} else if (value > 0xFFFF) {
is_one_byte_string = false;
is_two_byte_string = false;
} else if (value > 0xFF) {
is_one_byte_string = false;
}
temp[i] = value;
}
if (is_one_byte_string) {
return OneByteString::New(temp, len, Heap::kNew);
} else if (is_two_byte_string) {
return TwoByteString::New(temp, len, Heap::kNew);
} else {
return FourByteString::New(temp, len, Heap::kNew);
}
}
DEFINE_NATIVE_ENTRY(StringBase_substringUnchecked, 3) {
GET_NATIVE_ARGUMENT(String, receiver, arguments->At(0));
GET_NATIVE_ARGUMENT(Smi, start_obj, arguments->At(1));
GET_NATIVE_ARGUMENT(Smi, end_obj, arguments->At(2));
intptr_t start = start_obj.Value();
intptr_t end = end_obj.Value();
return String::SubString(receiver, start, (end - start));
}
DEFINE_NATIVE_ENTRY(String_hashCode, 1) {
const String& receiver = String::CheckedHandle(arguments->At(0));
intptr_t hash_val = receiver.Hash();
ASSERT(hash_val > 0);
ASSERT(Smi::IsValid(hash_val));
return Smi::New(hash_val);
}
DEFINE_NATIVE_ENTRY(String_getLength, 1) {
const String& receiver = String::CheckedHandle(arguments->At(0));
return Smi::New(receiver.Length());
}
static int32_t StringValueAt(const String& str, const Integer& index) {
if (index.IsSmi()) {
Smi& smi = Smi::Handle();
smi ^= index.raw();
int32_t index = smi.Value();
if ((index < 0) || (index >= str.Length())) {
GrowableArray<const Object*> arguments;
arguments.Add(&smi);
Exceptions::ThrowByType(Exceptions::kIndexOutOfRange, arguments);
}
return str.CharAt(index);
} else {
// An index larger than Smi is always illegal.
GrowableArray<const Object*> arguments;
arguments.Add(&index);
Exceptions::ThrowByType(Exceptions::kIndexOutOfRange, arguments);
return 0;
}
}
DEFINE_NATIVE_ENTRY(String_charAt, 2) {
const String& receiver = String::CheckedHandle(arguments->At(0));
GET_NATIVE_ARGUMENT(Integer, index, arguments->At(1));
uint32_t value = StringValueAt(receiver, index);
ASSERT(value <= 0x10FFFF);
return Symbols::New(&value, 1);
}
DEFINE_NATIVE_ENTRY(String_charCodeAt, 2) {
const String& receiver = String::CheckedHandle(arguments->At(0));
GET_NATIVE_ARGUMENT(Integer, index, arguments->At(1));
int32_t value = StringValueAt(receiver, index);
ASSERT(value >= 0);
ASSERT(value <= 0x10FFFF);
return Smi::New(value);
}
DEFINE_NATIVE_ENTRY(String_concat, 2) {
const String& receiver = String::CheckedHandle(arguments->At(0));
GET_NATIVE_ARGUMENT(String, b, arguments->At(1));
return String::Concat(receiver, b);
}
DEFINE_NATIVE_ENTRY(String_toLowerCase, 1) {
const String& receiver = String::CheckedHandle(arguments->At(0));
ASSERT(!receiver.IsNull());
return String::ToLowerCase(receiver);
}
DEFINE_NATIVE_ENTRY(String_toUpperCase, 1) {
const String& receiver = String::CheckedHandle(arguments->At(0));
ASSERT(!receiver.IsNull());
return String::ToUpperCase(receiver);
}
DEFINE_NATIVE_ENTRY(Strings_concatAll, 1) {
GET_NATIVE_ARGUMENT(Array, strings, arguments->At(0));
ASSERT(!strings.IsNull());
// Check that the array contains strings.
Instance& elem = Instance::Handle();
for (intptr_t i = 0; i < strings.Length(); i++) {
elem ^= strings.At(i);
if (elem.IsNull()) {
GrowableArray<const Object*> args;
Exceptions::ThrowByType(Exceptions::kNullPointer, args);
}
if (!elem.IsString()) {
GrowableArray<const Object*> args;
args.Add(&elem);
Exceptions::ThrowByType(Exceptions::kArgument, args);
}
}
return String::ConcatAll(strings);
}
} // namespace dart