| Index: src/runtime.cc
 | 
| diff --git a/src/runtime.cc b/src/runtime.cc
 | 
| index d804979d2e3927e1affde0146643f534e96fdf07..ead0281844459e1ba47f65dd542e102ef654f3a3 100644
 | 
| --- a/src/runtime.cc
 | 
| +++ b/src/runtime.cc
 | 
| @@ -58,6 +58,7 @@
 | 
|  #include "smart-pointers.h"
 | 
|  #include "string-search.h"
 | 
|  #include "stub-cache.h"
 | 
| +#include "uri.h"
 | 
|  #include "v8threads.h"
 | 
|  #include "vm-state-inl.h"
 | 
|  
 | 
| @@ -5126,201 +5127,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// kNotEscaped is generated by the following:
 | 
| -//
 | 
| -// #!/bin/perl
 | 
| -// for (my $i = 0; $i < 256; $i++) {
 | 
| -//   print "\n" if $i % 16 == 0;
 | 
| -//   my $c = chr($i);
 | 
| -//   my $escaped = 1;
 | 
| -//   $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
 | 
| -//   print $escaped ? "0, " : "1, ";
 | 
| -// }
 | 
| -
 | 
| -
 | 
| -static bool IsNotEscaped(uint16_t character) {
 | 
| -  // Only for 8 bit characters, the rest are always escaped (in a different way)
 | 
| -  ASSERT(character < 256);
 | 
| -  static const char kNotEscaped[256] = {
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
 | 
| -    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
 | 
| -    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
| -    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
 | 
| -    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
| -    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
| -  };
 | 
| -  return kNotEscaped[character] != 0;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
 | 
| -  const char hex_chars[] = "0123456789ABCDEF";
 | 
| -  NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 1);
 | 
| -  CONVERT_ARG_CHECKED(String, source, 0);
 | 
| -
 | 
| -  source->TryFlatten();
 | 
| -
 | 
| -  int escaped_length = 0;
 | 
| -  int length = source->length();
 | 
| -  {
 | 
| -    Access<ConsStringIteratorOp> op(
 | 
| -        isolate->runtime_state()->string_iterator());
 | 
| -    StringCharacterStream stream(source, op.value());
 | 
| -    while (stream.HasMore()) {
 | 
| -      uint16_t character = stream.GetNext();
 | 
| -      if (character >= 256) {
 | 
| -        escaped_length += 6;
 | 
| -      } else if (IsNotEscaped(character)) {
 | 
| -        escaped_length++;
 | 
| -      } else {
 | 
| -        escaped_length += 3;
 | 
| -      }
 | 
| -      // We don't allow strings that are longer than a maximal length.
 | 
| -      ASSERT(String::kMaxLength < 0x7fffffff - 6);  // Cannot overflow.
 | 
| -      if (escaped_length > String::kMaxLength) {
 | 
| -        isolate->context()->mark_out_of_memory();
 | 
| -        return Failure::OutOfMemoryException(0x12);
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -  // No length change implies no change.  Return original string if no change.
 | 
| -  if (escaped_length == length) {
 | 
| -    return source;
 | 
| -  }
 | 
| -  Object* o;
 | 
| -  { MaybeObject* maybe_o =
 | 
| -        isolate->heap()->AllocateRawOneByteString(escaped_length);
 | 
| -    if (!maybe_o->ToObject(&o)) return maybe_o;
 | 
| -  }
 | 
| -  String* destination = String::cast(o);
 | 
| -  int dest_position = 0;
 | 
| -
 | 
| -  Access<ConsStringIteratorOp> op(
 | 
| -      isolate->runtime_state()->string_iterator());
 | 
| -  StringCharacterStream stream(source, op.value());
 | 
| -  while (stream.HasMore()) {
 | 
| -    uint16_t chr = stream.GetNext();
 | 
| -    if (chr >= 256) {
 | 
| -      destination->Set(dest_position, '%');
 | 
| -      destination->Set(dest_position+1, 'u');
 | 
| -      destination->Set(dest_position+2, hex_chars[chr >> 12]);
 | 
| -      destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
 | 
| -      destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
 | 
| -      destination->Set(dest_position+5, hex_chars[chr & 0xf]);
 | 
| -      dest_position += 6;
 | 
| -    } else if (IsNotEscaped(chr)) {
 | 
| -      destination->Set(dest_position, chr);
 | 
| -      dest_position++;
 | 
| -    } else {
 | 
| -      destination->Set(dest_position, '%');
 | 
| -      destination->Set(dest_position+1, hex_chars[chr >> 4]);
 | 
| -      destination->Set(dest_position+2, hex_chars[chr & 0xf]);
 | 
| -      dest_position += 3;
 | 
| -    }
 | 
| -  }
 | 
| -  return destination;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
 | 
| -  static const signed char kHexValue['g'] = {
 | 
| -    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
| -    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
| -    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
| -    0,  1,  2,   3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
 | 
| -    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
| -    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
| -    -1, 10, 11, 12, 13, 14, 15 };
 | 
| -
 | 
| -  if (character1 > 'f') return -1;
 | 
| -  int hi = kHexValue[character1];
 | 
| -  if (hi == -1) return -1;
 | 
| -  if (character2 > 'f') return -1;
 | 
| -  int lo = kHexValue[character2];
 | 
| -  if (lo == -1) return -1;
 | 
| -  return (hi << 4) + lo;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static inline int Unescape(String* source,
 | 
| -                           int i,
 | 
| -                           int length,
 | 
| -                           int* step) {
 | 
| -  uint16_t character = source->Get(i);
 | 
| -  int32_t hi = 0;
 | 
| -  int32_t lo = 0;
 | 
| -  if (character == '%' &&
 | 
| -      i <= length - 6 &&
 | 
| -      source->Get(i + 1) == 'u' &&
 | 
| -      (hi = TwoDigitHex(source->Get(i + 2),
 | 
| -                        source->Get(i + 3))) != -1 &&
 | 
| -      (lo = TwoDigitHex(source->Get(i + 4),
 | 
| -                        source->Get(i + 5))) != -1) {
 | 
| -    *step = 6;
 | 
| -    return (hi << 8) + lo;
 | 
| -  } else if (character == '%' &&
 | 
| -      i <= length - 3 &&
 | 
| -      (lo = TwoDigitHex(source->Get(i + 1),
 | 
| -                        source->Get(i + 2))) != -1) {
 | 
| -    *step = 3;
 | 
| -    return lo;
 | 
| -  } else {
 | 
| -    *step = 1;
 | 
| -    return character;
 | 
| -  }
 | 
| +  HandleScope scope(isolate);
 | 
| +  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
 | 
| +  Handle<String> string = FlattenGetString(source);
 | 
| +  String::FlatContent content = string->GetFlatContent();
 | 
| +  ASSERT(content.IsFlat());
 | 
| +  Handle<String> result =
 | 
| +      content.IsAscii() ? URIEscape::Escape<uint8_t>(isolate, source)
 | 
| +                        : URIEscape::Escape<uc16>(isolate, source);
 | 
| +  if (result.is_null()) return Failure::OutOfMemoryException(0x12);
 | 
| +  return *result;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
 | 
| -  NoHandleAllocation ha;
 | 
|    ASSERT(args.length() == 1);
 | 
| -  CONVERT_ARG_CHECKED(String, source, 0);
 | 
| -
 | 
| -  source->TryFlatten();
 | 
| -
 | 
| -  bool one_byte = true;
 | 
| -  int length = source->length();
 | 
| -
 | 
| -  int unescaped_length = 0;
 | 
| -  for (int i = 0; i < length; unescaped_length++) {
 | 
| -    int step;
 | 
| -    if (Unescape(source, i, length, &step) > String::kMaxOneByteCharCode) {
 | 
| -      one_byte = false;
 | 
| -    }
 | 
| -    i += step;
 | 
| -  }
 | 
| -
 | 
| -  // No length change implies no change.  Return original string if no change.
 | 
| -  if (unescaped_length == length)
 | 
| -    return source;
 | 
| -
 | 
| -  Object* o;
 | 
| -  { MaybeObject* maybe_o =
 | 
| -        one_byte ?
 | 
| -        isolate->heap()->AllocateRawOneByteString(unescaped_length) :
 | 
| -        isolate->heap()->AllocateRawTwoByteString(unescaped_length);
 | 
| -    if (!maybe_o->ToObject(&o)) return maybe_o;
 | 
| -  }
 | 
| -  String* destination = String::cast(o);
 | 
| -
 | 
| -  int dest_position = 0;
 | 
| -  for (int i = 0; i < length; dest_position++) {
 | 
| -    int step;
 | 
| -    destination->Set(dest_position, Unescape(source, i, length, &step));
 | 
| -    i += step;
 | 
| -  }
 | 
| -  return destination;
 | 
| +  HandleScope scope(isolate);
 | 
| +  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
 | 
| +  Handle<String> string = FlattenGetString(source);
 | 
| +  String::FlatContent content = string->GetFlatContent();
 | 
| +  ASSERT(content.IsFlat());
 | 
| +  return content.IsAscii() ? *URIUnescape::Unescape<uint8_t>(isolate, source)
 | 
| +                           : *URIUnescape::Unescape<uc16>(isolate, source);
 | 
|  }
 | 
|  
 | 
|  
 | 
| 
 |