| Index: dart/runtime/vm/object.cc
|
| ===================================================================
|
| --- dart/runtime/vm/object.cc (revision 31530)
|
| +++ dart/runtime/vm/object.cc (working copy)
|
| @@ -1808,6 +1808,128 @@
|
| }
|
|
|
|
|
| +intptr_t Class::FindFunctionIndex(const Function& needle) const {
|
| + Isolate* isolate = Isolate::Current();
|
| + if (EnsureIsFinalized(isolate) != Error::null()) {
|
| + return -1;
|
| + }
|
| + ReusableHandleScope reused_handles(isolate);
|
| + Array& funcs = reused_handles.ArrayHandle();
|
| + funcs ^= functions();
|
| + ASSERT(!funcs.IsNull());
|
| + Function& function = reused_handles.FunctionHandle();
|
| + const intptr_t len = funcs.Length();
|
| + for (intptr_t i = 0; i < len; i++) {
|
| + function ^= funcs.At(i);
|
| + if (function.raw() == needle.raw()) {
|
| + return i;
|
| + }
|
| + }
|
| + // No function found.
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +RawFunction* Class::FunctionFromIndex(intptr_t idx) const {
|
| + const Array& funcs = Array::Handle(functions());
|
| + if ((idx < 0) || (idx >= funcs.Length())) {
|
| + return Function::null();
|
| + }
|
| + Function& func = Function::Handle();
|
| + func ^= funcs.At(idx);
|
| + ASSERT(!func.IsNull());
|
| + return func.raw();
|
| +}
|
| +
|
| +
|
| +RawFunction* Class::ImplicitClosureFunctionFromIndex(intptr_t idx) const {
|
| + const Array& funcs = Array::Handle(functions());
|
| + if ((idx < 0) || (idx >= funcs.Length())) {
|
| + return Function::null();
|
| + }
|
| + Function& func = Function::Handle();
|
| + func ^= funcs.At(idx);
|
| + ASSERT(!func.IsNull());
|
| + if (!func.HasImplicitClosureFunction()) {
|
| + return Function::null();
|
| + }
|
| + const Function& closure_func =
|
| + Function::Handle(func.ImplicitClosureFunction());
|
| + ASSERT(!closure_func.IsNull());
|
| + return closure_func.raw();
|
| +}
|
| +
|
| +
|
| +intptr_t Class::FindImplicitClosureFunctionIndex(const Function& needle) const {
|
| + Isolate* isolate = Isolate::Current();
|
| + if (EnsureIsFinalized(isolate) != Error::null()) {
|
| + return -1;
|
| + }
|
| + ReusableHandleScope reused_handles(isolate);
|
| + Array& funcs = reused_handles.ArrayHandle();
|
| + funcs ^= functions();
|
| + ASSERT(!funcs.IsNull());
|
| + Function& function = reused_handles.FunctionHandle();
|
| + Function& implicit_closure = Function::Handle();
|
| + const intptr_t len = funcs.Length();
|
| + for (intptr_t i = 0; i < len; i++) {
|
| + function ^= funcs.At(i);
|
| + implicit_closure ^= function.implicit_closure_function();
|
| + if (implicit_closure.IsNull()) {
|
| + // Skip non-implicit closure functions.
|
| + continue;
|
| + }
|
| + if (needle.raw() == implicit_closure.raw()) {
|
| + return i;
|
| + }
|
| + }
|
| + // No function found.
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +
|
| +intptr_t Class::FindInvocationDispatcherFunctionIndex(
|
| + const Function& needle) const {
|
| + Isolate* isolate = Isolate::Current();
|
| + if (EnsureIsFinalized(isolate) != Error::null()) {
|
| + return -1;
|
| + }
|
| + ReusableHandleScope reused_handles(isolate);
|
| + Array& funcs = reused_handles.ArrayHandle();
|
| + funcs ^= invocation_dispatcher_cache();
|
| + ASSERT(!funcs.IsNull());
|
| + Object& object = reused_handles.ObjectHandle();
|
| + const intptr_t len = funcs.Length();
|
| + for (intptr_t i = 0; i < len; i++) {
|
| + object = funcs.At(i);
|
| + // The invocation_dispatcher_cache is a table with some entries that
|
| + // are functions.
|
| + if (object.IsFunction()) {
|
| + if (Function::Cast(object).raw() == needle.raw()) {
|
| + return i;
|
| + }
|
| + }
|
| + }
|
| + // No function found.
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +
|
| +RawFunction* Class::InvocationDispatcherFunctionFromIndex(intptr_t idx) const {
|
| + ReusableHandleScope reused_handles(Isolate::Current());
|
| + Array& dispatcher_cache = reused_handles.ArrayHandle();
|
| + dispatcher_cache ^= invocation_dispatcher_cache();
|
| + Object& object = reused_handles.ObjectHandle();
|
| + object = dispatcher_cache.At(idx);
|
| + if (!object.IsFunction()) {
|
| + return Function::null();
|
| + }
|
| + return Function::Cast(object).raw();
|
| +}
|
| +
|
| +
|
| void Class::AddClosureFunction(const Function& function) const {
|
| GrowableObjectArray& closures =
|
| GrowableObjectArray::Handle(raw_ptr()->closure_functions_);
|
| @@ -1848,7 +1970,40 @@
|
| return closure.raw();
|
| }
|
|
|
| +intptr_t Class::FindClosureIndex(const Function& needle) const {
|
| + if (closures() == GrowableObjectArray::null()) {
|
| + return -1;
|
| + }
|
| + Isolate* isolate = Isolate::Current();
|
| + ReusableHandleScope reused_handles(isolate);
|
| + const GrowableObjectArray& closures_array =
|
| + GrowableObjectArray::Handle(isolate, closures());
|
| + Function& closure = reused_handles.FunctionHandle();
|
| + intptr_t num_closures = closures_array.Length();
|
| + for (intptr_t i = 0; i < num_closures; i++) {
|
| + closure ^= closures_array.At(i);
|
| + ASSERT(!closure.IsNull());
|
| + if (closure.raw() == needle.raw()) {
|
| + return i;
|
| + }
|
| + }
|
| + return -1;
|
| +}
|
|
|
| +
|
| +RawFunction* Class::ClosureFunctionFromIndex(intptr_t idx) const {
|
| + const GrowableObjectArray& closures_array =
|
| + GrowableObjectArray::Handle(closures());
|
| + if ((idx < 0) || (idx >= closures_array.Length())) {
|
| + return Function::null();
|
| + }
|
| + Function& func = Function::Handle();
|
| + func ^= closures_array.At(idx);
|
| + ASSERT(!func.IsNull());
|
| + return func.raw();
|
| +}
|
| +
|
| +
|
| void Class::set_signature_function(const Function& value) const {
|
| ASSERT(value.IsClosureFunction() || value.IsSignatureFunction());
|
| StorePointer(&raw_ptr()->signature_function_, value.raw());
|
| @@ -1985,6 +2140,7 @@
|
| break;
|
| }
|
| sup_type = cls.super_type();
|
| + ClassFinalizer::ResolveType(cls, sup_type);
|
| cls = sup_type.type_class();
|
| } while (true);
|
| set_num_type_arguments(num_type_args);
|
| @@ -2399,6 +2555,44 @@
|
| }
|
|
|
|
|
| +intptr_t Class::FindFieldIndex(const Field& needle) const {
|
| + Isolate* isolate = Isolate::Current();
|
| + if (EnsureIsFinalized(isolate) != Error::null()) {
|
| + return -1;
|
| + }
|
| + ReusableHandleScope reused_handles(isolate);
|
| + Array& fields_array = reused_handles.ArrayHandle();
|
| + fields_array ^= fields();
|
| + ASSERT(!fields_array.IsNull());
|
| + Field& field = reused_handles.FieldHandle();
|
| + String& field_name = reused_handles.StringHandle();
|
| + String& needle_name = String::Handle(isolate);
|
| + needle_name ^= needle.name();
|
| + const intptr_t len = fields_array.Length();
|
| + for (intptr_t i = 0; i < len; i++) {
|
| + field ^= fields_array.At(i);
|
| + field_name ^= field.name();
|
| + if (field_name.Equals(needle_name)) {
|
| + return i;
|
| + }
|
| + }
|
| + // No field found.
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +RawField* Class::FieldFromIndex(intptr_t idx) const {
|
| + const Array& flds = Array::Handle(fields());
|
| + if ((idx < 0) || (idx >= flds.Length())) {
|
| + return Field::null();
|
| + }
|
| + Field& field = Field::Handle();
|
| + field ^= flds.At(idx);
|
| + ASSERT(!field.IsNull());
|
| + return field.raw();
|
| +}
|
| +
|
| +
|
| template <class FakeInstance>
|
| RawClass* Class::New(intptr_t index) {
|
| ASSERT(Object::class_class() != Class::null());
|
| @@ -3248,7 +3442,7 @@
|
| const char* user_visible_class_name =
|
| String::Handle(UserVisibleName()).ToCString();
|
| jsobj.AddProperty("type", JSONType(ref));
|
| - jsobj.AddProperty("id", id());
|
| + jsobj.AddPropertyF("id", "classes/%" Pd "", id());
|
| jsobj.AddProperty("name", internal_class_name);
|
| jsobj.AddProperty("user_name", user_visible_class_name);
|
| if (!ref) {
|
| @@ -4011,6 +4205,19 @@
|
| }
|
|
|
|
|
| +RawAbstractTypeArguments* InstantiatedTypeArguments::Canonicalize() const {
|
| + const intptr_t num_types = Length();
|
| + const TypeArguments& type_args = TypeArguments::Handle(
|
| + TypeArguments::New(num_types, Heap::kOld));
|
| + AbstractType& type = AbstractType::Handle();
|
| + for (intptr_t i = 0; i < num_types; i++) {
|
| + type = TypeAt(i);
|
| + type_args.SetTypeAt(i, type);
|
| + }
|
| + return type_args.Canonicalize();
|
| +}
|
| +
|
| +
|
| void InstantiatedTypeArguments::set_uninstantiated_type_arguments(
|
| const AbstractTypeArguments& value) const {
|
| StorePointer(&raw_ptr()->uninstantiated_type_arguments_, value.raw());
|
| @@ -4360,6 +4567,54 @@
|
| }
|
|
|
|
|
| +const char* Function::KindToCString(RawFunction::Kind kind) {
|
| + switch (kind) {
|
| + case RawFunction::kRegularFunction:
|
| + return "kRegularFunction";
|
| + break;
|
| + case RawFunction::kClosureFunction:
|
| + return "kClosureFunction";
|
| + break;
|
| + case RawFunction::kSignatureFunction:
|
| + return "kSignatureFunction";
|
| + break;
|
| + case RawFunction::kGetterFunction:
|
| + return "kGetterFunction";
|
| + break;
|
| + case RawFunction::kSetterFunction:
|
| + return "kSetterFunction";
|
| + break;
|
| + case RawFunction::kConstructor:
|
| + return "kConstructor";
|
| + break;
|
| + case RawFunction::kImplicitGetter:
|
| + return "kImplicitGetter";
|
| + break;
|
| + case RawFunction::kImplicitSetter:
|
| + return "kImplicitSetter";
|
| + break;
|
| + case RawFunction::kImplicitStaticFinalGetter:
|
| + return "kImplicitStaticFinalGetter";
|
| + break;
|
| + case RawFunction::kStaticInitializer:
|
| + return "kStaticInitializer";
|
| + break;
|
| + case RawFunction::kMethodExtractor:
|
| + return "kMethodExtractor";
|
| + break;
|
| + case RawFunction::kNoSuchMethodDispatcher:
|
| + return "kNoSuchMethodDispatcher";
|
| + break;
|
| + case RawFunction::kInvokeFieldDispatcher:
|
| + return "kInvokeFieldDispatcher";
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + return NULL;
|
| + }
|
| +}
|
| +
|
| +
|
| void Function::SetRedirectionType(const Type& type) const {
|
| ASSERT(IsFactory());
|
| Object& obj = Object::Handle(raw_ptr()->data_);
|
| @@ -5619,11 +5874,31 @@
|
| const char* internal_function_name = String::Handle(name()).ToCString();
|
| const char* function_name =
|
| String::Handle(QualifiedUserVisibleName()).ToCString();
|
| - ObjectIdRing* ring = Isolate::Current()->object_id_ring();
|
| - intptr_t id = ring->GetIdForObject(raw());
|
| + Class& cls = Class::Handle(Owner());
|
| + ASSERT(!cls.IsNull());
|
| + Error& err = Error::Handle();
|
| + err ^= cls.EnsureIsFinalized(Isolate::Current());
|
| + ASSERT(err.IsNull());
|
| + intptr_t id = -1;
|
| + const char* selector = NULL;
|
| + if (IsNonImplicitClosureFunction()) {
|
| + id = cls.FindClosureIndex(*this);
|
| + selector = "closures";
|
| + } else if (IsImplicitClosureFunction()) {
|
| + id = cls.FindImplicitClosureFunctionIndex(*this);
|
| + selector = "implicit_closures";
|
| + } else if (IsNoSuchMethodDispatcher() || IsInvokeFieldDispatcher()) {
|
| + id = cls.FindInvocationDispatcherFunctionIndex(*this);
|
| + selector = "dispatchers";
|
| + } else {
|
| + id = cls.FindFunctionIndex(*this);
|
| + selector = "functions";
|
| + }
|
| + ASSERT(id >= 0);
|
| + intptr_t cid = cls.id();
|
| JSONObject jsobj(stream);
|
| jsobj.AddProperty("type", JSONType(ref));
|
| - jsobj.AddProperty("id", id);
|
| + jsobj.AddPropertyF("id", "classes/%" Pd "/%s/%" Pd "", cid, selector, id);
|
| jsobj.AddProperty("name", internal_function_name);
|
| jsobj.AddProperty("user_name", function_name);
|
| if (ref) return;
|
| @@ -5631,44 +5906,7 @@
|
| jsobj.AddProperty("is_const", is_const());
|
| jsobj.AddProperty("is_optimizable", is_optimizable());
|
| jsobj.AddProperty("is_inlinable", IsInlineable());
|
| - const char* kind_string = NULL;
|
| - switch (kind()) {
|
| - case RawFunction::kRegularFunction:
|
| - kind_string = "regular";
|
| - break;
|
| - case RawFunction::kGetterFunction:
|
| - kind_string = "getter";
|
| - break;
|
| - case RawFunction::kSetterFunction:
|
| - kind_string = "setter";
|
| - break;
|
| - case RawFunction::kImplicitGetter:
|
| - kind_string = "implicit getter";
|
| - break;
|
| - case RawFunction::kImplicitSetter:
|
| - kind_string = "implicit setter";
|
| - break;
|
| - case RawFunction::kMethodExtractor:
|
| - kind_string = "method extractor";
|
| - break;
|
| - case RawFunction::kNoSuchMethodDispatcher:
|
| - kind_string = "no such method";
|
| - break;
|
| - case RawFunction::kClosureFunction:
|
| - kind_string = "closure";
|
| - break;
|
| - case RawFunction::kConstructor:
|
| - kind_string = "constructor";
|
| - break;
|
| - case RawFunction::kStaticInitializer:
|
| - kind_string = "static initializer";
|
| - break;
|
| - case RawFunction::kImplicitStaticFinalGetter:
|
| - kind_string = "static final getter";
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| + const char* kind_string = Function::KindToCString(kind());
|
| jsobj.AddProperty("kind", kind_string);
|
| jsobj.AddProperty("unoptimized_code", Object::Handle(unoptimized_code()));
|
| jsobj.AddProperty("usage_counter", usage_counter());
|
| @@ -5952,10 +6190,12 @@
|
| JSONObject jsobj(stream);
|
| const char* internal_field_name = String::Handle(name()).ToCString();
|
| const char* field_name = String::Handle(UserVisibleName()).ToCString();
|
| - ObjectIdRing* ring = Isolate::Current()->object_id_ring();
|
| - intptr_t id = ring->GetIdForObject(raw());
|
| + Class& cls = Class::Handle(owner());
|
| + intptr_t id = cls.FindFieldIndex(*this);
|
| + ASSERT(id >= 0);
|
| + intptr_t cid = cls.id();
|
| jsobj.AddProperty("type", JSONType(ref));
|
| - jsobj.AddProperty("id", id);
|
| + jsobj.AddPropertyF("id", "classes/%" Pd "/fields/%" Pd "", cid, id);
|
| jsobj.AddProperty("name", internal_field_name);
|
| jsobj.AddProperty("user_name", field_name);
|
| if (is_static()) {
|
| @@ -5965,7 +6205,7 @@
|
| const Object& valueObj = Object::Handle(instance.GetField(*this));
|
| jsobj.AddProperty("value", valueObj);
|
| }
|
| - Class& cls = Class::Handle(owner());
|
| +
|
| jsobj.AddProperty("owner", cls);
|
| AbstractType& declared_type = AbstractType::Handle(type());
|
| cls = declared_type.type_class();
|
| @@ -7119,12 +7359,14 @@
|
|
|
| void Script::PrintToJSONStream(JSONStream* stream, bool ref) const {
|
| JSONObject jsobj(stream);
|
| - ObjectIdRing* ring = Isolate::Current()->object_id_ring();
|
| - intptr_t id = ring->GetIdForObject(raw());
|
| jsobj.AddProperty("type", JSONType(ref));
|
| - jsobj.AddProperty("id", id);
|
| const String& name = String::Handle(url());
|
| + ASSERT(!name.IsNull());
|
| + const String& encoded_url = String::Handle(String::EncodeURI(name));
|
| + ASSERT(!encoded_url.IsNull());
|
| + jsobj.AddPropertyF("id", "scripts/%s", encoded_url.ToCString());
|
| jsobj.AddProperty("name", name.ToCString());
|
| + jsobj.AddProperty("user_name", name.ToCString());
|
| jsobj.AddProperty("kind", GetKindAsCString());
|
| if (ref) {
|
| return;
|
| @@ -8193,13 +8435,13 @@
|
| void Library::PrintToJSONStream(JSONStream* stream, bool ref) const {
|
| const char* library_name = String::Handle(name()).ToCString();
|
| const char* library_url = String::Handle(url()).ToCString();
|
| - ObjectIdRing* ring = Isolate::Current()->object_id_ring();
|
| - intptr_t id = ring->GetIdForObject(raw());
|
| + intptr_t id = index();
|
| + ASSERT(id >= 0);
|
| JSONObject jsobj(stream);
|
| jsobj.AddProperty("type", JSONType(ref));
|
| - jsobj.AddProperty("id", id);
|
| + jsobj.AddPropertyF("id", "libraries/%" Pd "", id);
|
| jsobj.AddProperty("name", library_name);
|
| - jsobj.AddProperty("url", library_url);
|
| + jsobj.AddProperty("user_name", library_url);
|
| if (ref) return;
|
| {
|
| JSONArray jsarr(&jsobj, "classes");
|
| @@ -9581,10 +9823,26 @@
|
| }
|
|
|
|
|
| -void Code::Disassemble() const {
|
| +void Code::Disassemble(DisassemblyFormatter* formatter) const {
|
| + const bool fix_patch = CodePatcher::CodeIsPatchable(*this) &&
|
| + CodePatcher::IsEntryPatched(*this);
|
| + if (fix_patch) {
|
| + // The disassembler may choke on illegal instructions if the code has been
|
| + // patched, un-patch the code before disassembling and re-patch after.
|
| + CodePatcher::RestoreEntry(*this);
|
| + }
|
| const Instructions& instr = Instructions::Handle(instructions());
|
| uword start = instr.EntryPoint();
|
| - Disassembler::Disassemble(start, start + instr.size(), comments());
|
| + if (formatter == NULL) {
|
| + Disassembler::Disassemble(start, start + instr.size(), comments());
|
| + } else {
|
| + Disassembler::Disassemble(start, start + instr.size(), formatter,
|
| + comments());
|
| + }
|
| + if (fix_patch) {
|
| + // Redo the patch.
|
| + CodePatcher::PatchEntry(*this);
|
| + }
|
| }
|
|
|
|
|
| @@ -9696,7 +9954,7 @@
|
|
|
|
|
| // Check if object matches find condition.
|
| -bool Code::FindRawCodeVisitor::FindObject(RawObject* obj) {
|
| +bool Code::FindRawCodeVisitor::FindObject(RawObject* obj) const {
|
| return RawInstructions::ContainsPC(obj, pc_);
|
| }
|
|
|
| @@ -9766,25 +10024,33 @@
|
|
|
|
|
| void Code::PrintToJSONStream(JSONStream* stream, bool ref) const {
|
| - ObjectIdRing* ring = Isolate::Current()->object_id_ring();
|
| - intptr_t id = ring->GetIdForObject(raw());
|
| JSONObject jsobj(stream);
|
| + jsobj.AddProperty("type", JSONType(ref));
|
| + jsobj.AddPropertyF("id", "code/%" Px "", EntryPoint());
|
| + jsobj.AddPropertyF("start", "%" Px "", EntryPoint());
|
| + jsobj.AddPropertyF("end", "%" Px "", EntryPoint() + Size());
|
| + Function& func = Function::Handle();
|
| + func ^= function();
|
| + ASSERT(!func.IsNull());
|
| + String& name = String::Handle();
|
| + ASSERT(!func.IsNull());
|
| + name ^= func.name();
|
| + const char* internal_function_name = name.ToCString();
|
| + jsobj.AddPropertyF("name", "%s%s", is_optimized() ? "*" : "",
|
| + internal_function_name);
|
| + name ^= func.QualifiedUserVisibleName();
|
| + const char* function_name = name.ToCString();
|
| + jsobj.AddPropertyF("user_name", "%s%s", is_optimized() ? "*" : "",
|
| + function_name);
|
| if (ref) {
|
| - jsobj.AddProperty("type", "@Code");
|
| - jsobj.AddProperty("id", id);
|
| return;
|
| }
|
| - jsobj.AddProperty("type", "Code");
|
| - jsobj.AddProperty("id", id);
|
| jsobj.AddProperty("is_optimized", is_optimized());
|
| jsobj.AddProperty("is_alive", is_alive());
|
| jsobj.AddProperty("function", Object::Handle(function()));
|
| JSONArray jsarr(&jsobj, "disassembly");
|
| DisassembleToJSONStream formatter(jsarr);
|
| - const Instructions& instr = Instructions::Handle(instructions());
|
| - uword start = instr.EntryPoint();
|
| - Disassembler::Disassemble(start, start + instr.size(), &formatter,
|
| - comments());
|
| + Disassemble(&formatter);
|
| }
|
|
|
|
|
| @@ -11477,7 +11743,7 @@
|
|
|
| JSONObject jsobj(stream);
|
| jsobj.AddProperty("type", JSONType(ref));
|
| - jsobj.AddProperty("id", id);
|
| + jsobj.AddPropertyF("id", "objects/%" Pd "", id);
|
|
|
| Class& cls = Class::Handle(this->clazz());
|
| jsobj.AddProperty("class", cls);
|
| @@ -12320,6 +12586,7 @@
|
| }
|
| #endif
|
| ASSERT(IsOld());
|
| + ASSERT(type_args.IsNull() || type_args.IsOld());
|
| SetCanonical();
|
| return this->raw();
|
| }
|
| @@ -14335,6 +14602,154 @@
|
| }
|
|
|
|
|
| +static bool IsPercent(int32_t c) {
|
| + return c == '%';
|
| +}
|
| +
|
| +
|
| +static bool IsHexCharacter(int32_t c) {
|
| + if (c >= '0' && c <= '9') {
|
| + return true;
|
| + }
|
| + if (c >= 'A' && c <= 'F') {
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| +static bool IsURISafeCharacter(int32_t c) {
|
| + if ((c >= '0') && (c <= '9')) {
|
| + return true;
|
| + }
|
| + if ((c >= 'a') && (c <= 'z')) {
|
| + return true;
|
| + }
|
| + if ((c >= 'A') && (c <= 'Z')) {
|
| + return true;
|
| + }
|
| + return (c == '-') || (c == '_') || (c == '.') || (c == '~');
|
| +}
|
| +
|
| +
|
| +static int32_t GetHexCharacter(int32_t c) {
|
| + ASSERT(c >= 0);
|
| + ASSERT(c < 16);
|
| + const char* hex = "0123456789ABCDEF";
|
| + return hex[c];
|
| +}
|
| +
|
| +
|
| +static int32_t GetHexValue(int32_t c) {
|
| + if (c >= '0' && c <= '9') {
|
| + return c - '0';
|
| + }
|
| + if (c >= 'A' && c <= 'F') {
|
| + return c - 'A' + 10;
|
| + }
|
| + UNREACHABLE();
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +static int32_t MergeHexCharacters(int32_t c1, int32_t c2) {
|
| + return GetHexValue(c1) << 4 | GetHexValue(c2);
|
| +}
|
| +
|
| +
|
| +RawString* String::EncodeURI(const String& str) {
|
| + // URI encoding is only specified for one byte strings.
|
| + ASSERT(str.IsOneByteString() || str.IsExternalOneByteString());
|
| + intptr_t num_escapes = 0;
|
| + intptr_t len = str.Length();
|
| + {
|
| + CodePointIterator cpi(str);
|
| + while (cpi.Next()) {
|
| + int32_t code_point = cpi.Current();
|
| + if (!IsURISafeCharacter(code_point)) {
|
| + num_escapes += 2;
|
| + }
|
| + }
|
| + }
|
| + const String& dststr = String::Handle(
|
| + OneByteString::New(len + num_escapes, Heap::kNew));
|
| + {
|
| + intptr_t index = 0;
|
| + CodePointIterator cpi(str);
|
| + while (cpi.Next()) {
|
| + int32_t code_point = cpi.Current();
|
| + if (!IsURISafeCharacter(code_point)) {
|
| + OneByteString::SetCharAt(dststr, index, '%');
|
| + OneByteString::SetCharAt(dststr, index + 1,
|
| + GetHexCharacter(code_point >> 4));
|
| + OneByteString::SetCharAt(dststr, index + 2,
|
| + GetHexCharacter(code_point & 0xF));
|
| + index += 3;
|
| + } else {
|
| + OneByteString::SetCharAt(dststr, index, code_point);
|
| + index += 1;
|
| + }
|
| + }
|
| + }
|
| + return dststr.raw();
|
| +}
|
| +
|
| +
|
| +RawString* String::DecodeURI(const String& str) {
|
| + // URI encoding is only specified for one byte strings.
|
| + ASSERT(str.IsOneByteString() || str.IsExternalOneByteString());
|
| + CodePointIterator cpi(str);
|
| + intptr_t num_escapes = 0;
|
| + intptr_t len = str.Length();
|
| + {
|
| + CodePointIterator cpi(str);
|
| + while (cpi.Next()) {
|
| + int32_t code_point = cpi.Current();
|
| + if (IsPercent(code_point)) {
|
| + // Verify that the two characters following the % are hex digits.
|
| + if (!cpi.Next()) {
|
| + return str.raw();
|
| + }
|
| + int32_t code_point = cpi.Current();
|
| + if (!IsHexCharacter(code_point)) {
|
| + return str.raw();
|
| + }
|
| + if (!cpi.Next()) {
|
| + return str.raw();
|
| + }
|
| + code_point = cpi.Current();
|
| + if (!IsHexCharacter(code_point)) {
|
| + return str.raw();
|
| + }
|
| + num_escapes += 2;
|
| + }
|
| + }
|
| + }
|
| + ASSERT(len - num_escapes > 0);
|
| + const String& dststr = String::Handle(
|
| + OneByteString::New(len - num_escapes, Heap::kNew));
|
| + {
|
| + intptr_t index = 0;
|
| + CodePointIterator cpi(str);
|
| + while (cpi.Next()) {
|
| + int32_t code_point = cpi.Current();
|
| + if (IsPercent(code_point)) {
|
| + cpi.Next();
|
| + int32_t ch1 = cpi.Current();
|
| + cpi.Next();
|
| + int32_t ch2 = cpi.Current();
|
| + int32_t merged = MergeHexCharacters(ch1, ch2);
|
| + OneByteString::SetCharAt(dststr, index, merged);
|
| + } else {
|
| + OneByteString::SetCharAt(dststr, index, code_point);
|
| + }
|
| + index++;
|
| + }
|
| + }
|
| + return dststr.raw();
|
| +}
|
| +
|
| +
|
| RawString* String::NewFormatted(const char* format, ...) {
|
| va_list args;
|
| va_start(args, format);
|
|
|