[builtins] Move EncodeURI from runtime to builtins.

Repackage encodeURI and encodeURIComponent as builtin functions
and install them in the bootstrapper.

Crude benchmark on 351 encodeURI and encodeURIComponent tests averaged
over five runs:

* builtin functions
real	0m8.01s
user	0m18.00s
sys	0m7.37s

* JS functions calling into the runtime e.g., for %NewString
real	0m8.44s
user	0m19.52s
sys	0m7.49s

By running:
$ time tools/run-tests.py   --arch=x64 --mode=Release --buildbot
mjsunit/uri test262/built-ins/encodeURI*
>>> Running tests for x64.Release

BUG=v8:4912
R=yangguo@chromium.org

Review-Url: https://codereview.chromium.org/1983593002
Cr-Commit-Position: refs/heads/master@{#36273}
This commit is contained in:
franzih 2016-05-17 03:54:14 -07:00 committed by Commit bot
parent f248a83d29
commit c60cb90c4f
10 changed files with 231 additions and 187 deletions

View File

@ -320,7 +320,7 @@ config("toolchain") {
template("v8_source_set") {
source_set(target_name) {
forward_variables_from(invoker, "*", ["configs"])
forward_variables_from(invoker, "*", [ "configs" ])
configs += invoker.configs
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
@ -667,9 +667,7 @@ v8_source_set("v8_nosnapshot") {
"src/snapshot/snapshot-empty.cc",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}
v8_source_set("v8_snapshot") {
@ -701,9 +699,7 @@ v8_source_set("v8_snapshot") {
"$target_gen_dir/snapshot.cc",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}
if (v8_use_external_startup_data) {
@ -727,9 +723,7 @@ if (v8_use_external_startup_data) {
"src/snapshot/snapshot-external.cc",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}
}
@ -1476,6 +1470,8 @@ v8_source_set("v8_base") {
"src/unicode-inl.h",
"src/unicode.cc",
"src/unicode.h",
"src/uri.cc",
"src/uri.h",
"src/utils-inl.h",
"src/utils.cc",
"src/utils.h",
@ -1822,9 +1818,7 @@ v8_source_set("v8_base") {
]
}
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
defines = []
deps = [
@ -1917,9 +1911,7 @@ v8_source_set("v8_libbase") {
"src/base/utils/random-number-generator.h",
]
configs = [
":internal_config_base",
]
configs = [ ":internal_config_base" ]
defines = []
@ -1979,13 +1971,9 @@ v8_source_set("v8_libplatform") {
"src/libplatform/worker-thread.h",
]
configs = [
":internal_config_base",
]
configs = [ ":internal_config_base" ]
public_configs = [
":libplatform_config"
]
public_configs = [ ":libplatform_config" ]
deps = [
":v8_libbase",
@ -2000,9 +1988,7 @@ v8_source_set("fuzzer_support") {
"test/fuzzer/fuzzer-support.h",
]
configs = [
":internal_config_base",
]
configs = [ ":internal_config_base" ]
deps = [
snapshot_target,
@ -2158,9 +2144,7 @@ v8_source_set("json_fuzzer") {
":fuzzer_support",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}
v8_source_set("parser_fuzzer") {
@ -2172,9 +2156,7 @@ v8_source_set("parser_fuzzer") {
":fuzzer_support",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}
v8_source_set("regexp_fuzzer") {
@ -2186,9 +2168,7 @@ v8_source_set("regexp_fuzzer") {
":fuzzer_support",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}
v8_source_set("wasm_fuzzer") {
@ -2200,9 +2180,7 @@ v8_source_set("wasm_fuzzer") {
":fuzzer_support",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}
v8_source_set("wasm_asmjs_fuzzer") {
@ -2214,7 +2192,5 @@ v8_source_set("wasm_asmjs_fuzzer") {
":fuzzer_support",
]
configs = [
":internal_config",
]
configs = [ ":internal_config" ]
}

View File

@ -2819,11 +2819,22 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
native_context()->set_string_function_prototype_map(
HeapObject::cast(string_function->initial_map()->prototype())->map());
Handle<JSGlobalObject> global_object =
handle(native_context()->global_object());
// Install Global.encodeURI.
SimpleInstallFunction(global_object, "encodeURI", Builtins::kGlobalEncodeURI,
1, false);
// Install Global.encodeURIComponent.
SimpleInstallFunction(global_object, "encodeURIComponent",
Builtins::kGlobalEncodeURIComponent, 1, false);
// Install Global.eval.
{
Handle<JSFunction> eval = SimpleInstallFunction(
handle(native_context()->global_object()), factory()->eval_string(),
Builtins::kGlobalEval, 1, false);
Handle<JSFunction> eval =
SimpleInstallFunction(global_object, factory()->eval_string(),
Builtins::kGlobalEval, 1, false);
native_context()->set_global_eval_fun(*eval);
}
@ -2866,8 +2877,7 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
{
Handle<String> key = factory()->Promise_string();
Handle<JSFunction> function = Handle<JSFunction>::cast(
JSReceiver::GetProperty(handle(native_context()->global_object()), key)
.ToHandleChecked());
JSReceiver::GetProperty(global_object, key).ToHandleChecked());
JSFunction::EnsureHasInitialMap(function);
function->initial_map()->set_instance_type(JS_PROMISE_TYPE);
function->shared()->set_construct_stub(

View File

@ -23,6 +23,7 @@
#include "src/property-descriptor.h"
#include "src/prototype.h"
#include "src/string-builder.h"
#include "src/uri.h"
#include "src/vm-state-inl.h"
namespace v8 {
@ -2106,6 +2107,26 @@ BUILTIN(ObjectSeal) {
return *object;
}
// ES6 section 18.2.6.4 encodeURI (uri)
BUILTIN(GlobalEncodeURI) {
HandleScope scope(isolate);
Handle<String> uri;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, uri, Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
return Uri::EncodeUri(isolate, uri);
}
// ES6 section 18.2.6.5 encodeURIComponenet (uriComponent)
BUILTIN(GlobalEncodeURIComponent) {
HandleScope scope(isolate);
Handle<String> uriComponent;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, uriComponent,
Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
return Uri::EncodeUriComponent(isolate, uriComponent);
}
namespace {

View File

@ -116,6 +116,9 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(GeneratorFunctionConstructor, kTargetAndNewTarget) \
V(AsyncFunctionConstructor, kTargetAndNewTarget) \
\
V(GlobalEncodeURI, kNone) \
V(GlobalEncodeURIComponent, kNone) \
\
V(GlobalEval, kTarget) \
\
V(MathAcos, kNone) \

View File

@ -219,18 +219,6 @@ function URIDecodeComponent(component) {
return Decode(component, reservedPredicate);
}
// ECMA-262 - 15.1.3.3.
function URIEncode(uri) {
uri = TO_STRING(uri);
return %URIEncode(uri, true);
}
// ECMA-262 - 15.1.3.4
function URIEncodeComponent(component) {
component = TO_STRING(component);
return %URIEncode(component, false);
}
// -------------------------------------------------------------------
// Install exported functions.
@ -240,9 +228,7 @@ utils.InstallFunctions(global, DONT_ENUM, [
"escape", URIEscapeJS,
"unescape", URIUnescapeJS,
"decodeURI", URIDecode,
"decodeURIComponent", URIDecodeComponent,
"encodeURI", URIEncode,
"encodeURIComponent", URIEncodeComponent
"decodeURIComponent", URIDecodeComponent
]);
})

View File

@ -5,7 +5,6 @@
#include "src/runtime/runtime-utils.h"
#include "src/arguments.h"
#include "src/char-predicates-inl.h"
#include "src/regexp/jsregexp-inl.h"
#include "src/string-builder.h"
#include "src/string-search.h"
@ -1152,131 +1151,6 @@ RUNTIME_FUNCTION(Runtime_NewString) {
return *result;
}
// anonymous namespace for URIEncode helper functions
namespace {
bool IsUnescapePredicateInUriComponent(uc16 c) {
if (IsAlphaNumeric(c)) {
return true;
}
switch (c) {
case '!':
case '\'':
case '(':
case ')':
case '*':
case '-':
case '.':
case '_':
case '~':
return true;
default:
return false;
}
}
bool IsUriSeparator(uc16 c) {
switch (c) {
case '#':
case ':':
case ';':
case '/':
case '?':
case '$':
case '&':
case '+':
case ',':
case '@':
case '=':
return true;
default:
return false;
}
}
void AddHexEncodedToBuffer(uint8_t octet, List<uint8_t>* buffer) {
buffer->Add('%');
buffer->Add(HexCharOfValue(octet >> 4));
buffer->Add(HexCharOfValue(octet & 0x0F));
}
void EncodeSingle(uc16 c, List<uint8_t>* buffer) {
uint8_t x = (c >> 12) & 0xF;
uint8_t y = (c >> 6) & 63;
uint8_t z = c & 63;
if (c <= 0x007F) {
AddHexEncodedToBuffer(c, buffer);
} else if (c <= 0x07FF) {
AddHexEncodedToBuffer(y + 192, buffer);
AddHexEncodedToBuffer(z + 128, buffer);
} else {
AddHexEncodedToBuffer(x + 224, buffer);
AddHexEncodedToBuffer(y + 128, buffer);
AddHexEncodedToBuffer(z + 128, buffer);
}
}
void EncodePair(uc16 cc1, uc16 cc2, List<uint8_t>* buffer) {
uint8_t u = ((cc1 >> 6) & 0xF) + 1;
uint8_t w = (cc1 >> 2) & 0xF;
uint8_t x = cc1 & 3;
uint8_t y = (cc2 >> 6) & 0xF;
uint8_t z = cc2 & 63;
AddHexEncodedToBuffer((u >> 2) + 240, buffer);
AddHexEncodedToBuffer((((u & 3) << 4) | w) + 128, buffer);
AddHexEncodedToBuffer(((x << 4) | y) + 128, buffer);
AddHexEncodedToBuffer(z + 128, buffer);
}
} // anonymous namespace
RUNTIME_FUNCTION(Runtime_URIEncode) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(String, uri, 0);
CONVERT_BOOLEAN_ARG_CHECKED(is_uri, 1);
uri = String::Flatten(uri);
int uri_length = uri->length();
List<uint8_t> buffer(uri_length);
{
DisallowHeapAllocation no_gc;
String::FlatContent uri_content = uri->GetFlatContent();
for (int k = 0; k < uri_length; k++) {
uc16 cc1 = uri_content.Get(k);
if (unibrow::Utf16::IsLeadSurrogate(cc1)) {
k++;
if (k < uri_length) {
uc16 cc2 = uri->Get(k);
if (unibrow::Utf16::IsTrailSurrogate(cc2)) {
EncodePair(cc1, cc2, &buffer);
continue;
}
}
} else if (!unibrow::Utf16::IsTrailSurrogate(cc1)) {
if (IsUnescapePredicateInUriComponent(cc1) ||
(is_uri && IsUriSeparator(cc1))) {
buffer.Add(cc1);
} else {
EncodeSingle(cc1, &buffer);
}
continue;
}
AllowHeapAllocation allocate_error_and_return;
THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewURIError());
}
}
Handle<String> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
isolate->factory()->NewStringFromOneByte(buffer.ToConstVector()));
return *result;
}
RUNTIME_FUNCTION(Runtime_StringLessThan) {
HandleScope handle_scope(isolate);

View File

@ -836,7 +836,6 @@ namespace internal {
F(StringTrim, 3, 1) \
F(TruncateString, 2, 1) \
F(NewString, 2, 1) \
F(URIEncode, 2, 1) \
F(StringLessThan, 2, 1) \
F(StringLessThanOrEqual, 2, 1) \
F(StringGreaterThan, 2, 1) \

135
src/uri.cc Normal file
View File

@ -0,0 +1,135 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/uri.h"
#include "src/char-predicates-inl.h"
#include "src/handles.h"
#include "src/isolate-inl.h"
#include "src/list.h"
namespace v8 {
namespace internal {
namespace { // anonymous namespace for EncodeURI helper functions
bool IsUnescapePredicateInUriComponent(uc16 c) {
if (IsAlphaNumeric(c)) {
return true;
}
switch (c) {
case '!':
case '\'':
case '(':
case ')':
case '*':
case '-':
case '.':
case '_':
case '~':
return true;
default:
return false;
}
}
bool IsUriSeparator(uc16 c) {
switch (c) {
case '#':
case ':':
case ';':
case '/':
case '?':
case '$':
case '&':
case '+':
case ',':
case '@':
case '=':
return true;
default:
return false;
}
}
void AddHexEncodedToBuffer(uint8_t octet, List<uint8_t>* buffer) {
buffer->Add('%');
buffer->Add(HexCharOfValue(octet >> 4));
buffer->Add(HexCharOfValue(octet & 0x0F));
}
void EncodeSingle(uc16 c, List<uint8_t>* buffer) {
uint8_t x = (c >> 12) & 0xF;
uint8_t y = (c >> 6) & 63;
uint8_t z = c & 63;
if (c <= 0x007F) {
AddHexEncodedToBuffer(c, buffer);
} else if (c <= 0x07FF) {
AddHexEncodedToBuffer(y + 192, buffer);
AddHexEncodedToBuffer(z + 128, buffer);
} else {
AddHexEncodedToBuffer(x + 224, buffer);
AddHexEncodedToBuffer(y + 128, buffer);
AddHexEncodedToBuffer(z + 128, buffer);
}
}
void EncodePair(uc16 cc1, uc16 cc2, List<uint8_t>* buffer) {
uint8_t u = ((cc1 >> 6) & 0xF) + 1;
uint8_t w = (cc1 >> 2) & 0xF;
uint8_t x = cc1 & 3;
uint8_t y = (cc2 >> 6) & 0xF;
uint8_t z = cc2 & 63;
AddHexEncodedToBuffer((u >> 2) + 240, buffer);
AddHexEncodedToBuffer((((u & 3) << 4) | w) + 128, buffer);
AddHexEncodedToBuffer(((x << 4) | y) + 128, buffer);
AddHexEncodedToBuffer(z + 128, buffer);
}
} // anonymous namespace
Object* Uri::Encode(Isolate* isolate, Handle<String> uri, bool is_uri) {
uri = String::Flatten(uri);
int uri_length = uri->length();
List<uint8_t> buffer(uri_length);
{
DisallowHeapAllocation no_gc;
String::FlatContent uri_content = uri->GetFlatContent();
for (int k = 0; k < uri_length; k++) {
uc16 cc1 = uri_content.Get(k);
if (unibrow::Utf16::IsLeadSurrogate(cc1)) {
k++;
if (k < uri_length) {
uc16 cc2 = uri->Get(k);
if (unibrow::Utf16::IsTrailSurrogate(cc2)) {
EncodePair(cc1, cc2, &buffer);
continue;
}
}
} else if (!unibrow::Utf16::IsTrailSurrogate(cc1)) {
if (IsUnescapePredicateInUriComponent(cc1) ||
(is_uri && IsUriSeparator(cc1))) {
buffer.Add(cc1);
} else {
EncodeSingle(cc1, &buffer);
}
continue;
}
AllowHeapAllocation allocate_error_and_return;
THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewURIError());
}
}
Handle<String> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
isolate->factory()->NewStringFromOneByte(buffer.ToConstVector()));
return *result;
}
} // namespace internal
} // namespace v8

38
src/uri.h Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_URI_H_
#define V8_URI_H_
#include "src/allocation.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
class Uri : public AllStatic {
public:
static Object* EncodeUri(Isolate* isolate, Handle<String> uri) {
return Encode(isolate, uri, true);
}
static Object* EncodeUriComponent(Isolate* isolate,
Handle<String> component) {
return Encode(isolate, component, false);
}
// DecodeUri
// DecodeUriComponent
// escape
// unescape
private:
static Object* Encode(Isolate* isolate, Handle<String> uri, bool is_uri);
// decode
};
} // namespace internal
} // namespace v8
#endif // V8_URI_H_

View File

@ -1131,6 +1131,8 @@
'unicode-cache.h',
'unicode-decoder.cc',
'unicode-decoder.h',
'uri.cc',
'uri.h',
'utils-inl.h',
'utils.cc',
'utils.h',