Commit 89f159b0 authored by cbruni's avatar cbruni Committed by Commit bot

[runtime] Port simple String.prototype.indexOf cases to TF Builtin

Many websites use simple calls to String.prototype.indexOf with either a
one character ASCII needle or needles bigger than the search string. This
CL adds a TFJ builtin for these simple cases, giving up to factor 5 speedup.

Drive-by-fix: Add default Object type to Arguments.at

BUG=

Review-Url: https://codereview.chromium.org/2539093002
Cr-Commit-Position: refs/heads/master@{#41760}
parent 63279611
......@@ -41,7 +41,8 @@ class Arguments BASE_EMBEDDED {
index * kPointerSize));
}
template <class S> Handle<S> at(int index) {
template <class S = Object>
Handle<S> at(int index) {
Object** value = &((*this)[index]);
// This cast checks that the object we're accessing does indeed have the
// expected type.
......
......@@ -35,7 +35,9 @@
#include "src/assembler.h"
#include <math.h>
#include <string.h>
#include <cmath>
#include "src/api.h"
#include "src/base/cpu.h"
#include "src/base/functional.h"
......@@ -1551,6 +1553,14 @@ ExternalReference ExternalReference::ieee754_tanh_function(Isolate* isolate) {
Redirect(isolate, FUNCTION_ADDR(base::ieee754::tanh), BUILTIN_FP_CALL));
}
void* libc_memchr(void* string, int character, size_t search_length) {
return memchr(string, character, search_length);
}
ExternalReference ExternalReference::libc_memchr_function(Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(libc_memchr)));
}
ExternalReference ExternalReference::page_flags(Page* page) {
return ExternalReference(reinterpret_cast<Address>(page) +
MemoryChunk::kFlagsOffset);
......
......@@ -1029,6 +1029,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference ieee754_tan_function(Isolate* isolate);
static ExternalReference ieee754_tanh_function(Isolate* isolate);
static ExternalReference libc_memchr_function(Isolate* isolate);
static ExternalReference page_flags(Page* page);
static ExternalReference ForDeoptEntry(Address entry);
......@@ -1117,6 +1119,7 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, ExternalReference);
// -----------------------------------------------------------------------------
// Utility functions
void* libc_memchr(void* string, int character, size_t search_length);
inline int NumberOfBitsSet(uint32_t x) {
unsigned int num_bits_set;
......
......@@ -151,7 +151,7 @@ MUST_USE_RESULT static Object* CallJsIntrinsic(Isolate* isolate,
int argc = args.length() - 1;
ScopedVector<Handle<Object>> argv(argc);
for (int i = 0; i < argc; ++i) {
argv[i] = args.at<Object>(i + 1);
argv[i] = args.at(i + 1);
}
RETURN_RESULT_OR_FAILURE(
isolate,
......
This diff is collapsed.
......@@ -43,8 +43,7 @@ MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate,
if (i > 1) builder.AppendCharacter(',');
Handle<String> param;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, param, Object::ToString(isolate, args.at<Object>(i)),
Object);
isolate, param, Object::ToString(isolate, args.at(i)), Object);
param = String::Flatten(param);
builder.AppendString(param);
// If the formal parameters string include ) - an illegal
......@@ -68,8 +67,7 @@ MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate,
if (argc > 0) {
Handle<String> body;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, body, Object::ToString(isolate, args.at<Object>(argc)),
Object);
isolate, body, Object::ToString(isolate, args.at(argc)), Object);
builder.AppendString(body);
}
builder.AppendCString("\n})");
......@@ -180,9 +178,9 @@ Object* DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
Handle<Object> this_arg = isolate->factory()->undefined_value();
ScopedVector<Handle<Object>> argv(std::max(0, args.length() - 2));
if (args.length() > 1) {
this_arg = args.at<Object>(1);
this_arg = args.at(1);
for (int i = 2; i < args.length(); ++i) {
argv[i - 2] = args.at<Object>(i);
argv[i - 2] = args.at(i);
}
}
Handle<JSBoundFunction> function;
......
......@@ -360,7 +360,7 @@ BUILTIN(MathHypot) {
bool one_arg_is_nan = false;
List<double> abs_values(length);
for (int i = 0; i < length; i++) {
Handle<Object> x = args.at<Object>(i + 1);
Handle<Object> x = args.at(i + 1);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x));
double abs_value = std::abs(x->Number());
......
......@@ -336,7 +336,7 @@ TF_BUILTIN(NumberParseInt, CodeStubAssembler) {
// ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits )
BUILTIN(NumberPrototypeToExponential) {
HandleScope scope(isolate);
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
// Unwrap the receiver {value}.
......@@ -379,7 +379,7 @@ BUILTIN(NumberPrototypeToExponential) {
// ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits )
BUILTIN(NumberPrototypeToFixed) {
HandleScope scope(isolate);
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
// Unwrap the receiver {value}.
......@@ -422,7 +422,7 @@ BUILTIN(NumberPrototypeToFixed) {
// ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] )
BUILTIN(NumberPrototypeToLocaleString) {
HandleScope scope(isolate);
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
// Unwrap the receiver {value}.
if (value->IsJSValue()) {
......@@ -442,7 +442,7 @@ BUILTIN(NumberPrototypeToLocaleString) {
// ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision )
BUILTIN(NumberPrototypeToPrecision) {
HandleScope scope(isolate);
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
Handle<Object> precision = args.atOrUndefined(isolate, 1);
// Unwrap the receiver {value}.
......@@ -486,7 +486,7 @@ BUILTIN(NumberPrototypeToPrecision) {
// ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
BUILTIN(NumberPrototypeToString) {
HandleScope scope(isolate);
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
Handle<Object> radix = args.atOrUndefined(isolate, 1);
// Unwrap the receiver {value}.
......
......@@ -162,7 +162,7 @@ BUILTIN(ObjectAssign) {
// second argument.
// 4. For each element nextSource of sources, in ascending index order,
for (int i = 2; i < args.length(); ++i) {
Handle<Object> next_source = args.at<Object>(i);
Handle<Object> next_source = args.at(i);
Maybe<bool> fast_assign = FastAssign(to, next_source);
if (fast_assign.IsNothing()) return isolate->heap()->exception();
if (fast_assign.FromJust()) continue;
......@@ -558,8 +558,8 @@ void Builtins::Generate_ObjectCreate(compiler::CodeAssemblerState* state) {
BUILTIN(ObjectDefineProperties) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> properties = args.at<Object>(2);
Handle<Object> target = args.at(1);
Handle<Object> properties = args.at(2);
RETURN_RESULT_OR_FAILURE(
isolate, JSReceiver::DefineProperties(isolate, target, properties));
......@@ -569,9 +569,9 @@ BUILTIN(ObjectDefineProperties) {
BUILTIN(ObjectDefineProperty) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> key = args.at<Object>(2);
Handle<Object> attributes = args.at<Object>(3);
Handle<Object> target = args.at(1);
Handle<Object> key = args.at(2);
Handle<Object> attributes = args.at(3);
return JSReceiver::DefineProperty(isolate, target, key, attributes);
}
......@@ -671,9 +671,9 @@ Object* ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
// https://tc39.github.io/ecma262/#sec-object.prototype.__defineGetter__
BUILTIN(ObjectDefineGetter) {
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0); // Receiver.
Handle<Object> name = args.at<Object>(1);
Handle<Object> getter = args.at<Object>(2);
Handle<Object> object = args.at(0); // Receiver.
Handle<Object> name = args.at(1);
Handle<Object> getter = args.at(2);
return ObjectDefineAccessor<ACCESSOR_GETTER>(isolate, object, name, getter);
}
......@@ -681,9 +681,9 @@ BUILTIN(ObjectDefineGetter) {
// https://tc39.github.io/ecma262/#sec-object.prototype.__defineSetter__
BUILTIN(ObjectDefineSetter) {
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0); // Receiver.
Handle<Object> name = args.at<Object>(1);
Handle<Object> setter = args.at<Object>(2);
Handle<Object> object = args.at(0); // Receiver.
Handle<Object> name = args.at(1);
Handle<Object> setter = args.at(2);
return ObjectDefineAccessor<ACCESSOR_SETTER>(isolate, object, name, setter);
}
......@@ -691,8 +691,8 @@ BUILTIN(ObjectDefineSetter) {
// https://tc39.github.io/ecma262/#sec-object.prototype.__lookupGetter__
BUILTIN(ObjectLookupGetter) {
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0);
Handle<Object> name = args.at<Object>(1);
Handle<Object> object = args.at(0);
Handle<Object> name = args.at(1);
return ObjectLookupAccessor(isolate, object, name, ACCESSOR_GETTER);
}
......@@ -700,8 +700,8 @@ BUILTIN(ObjectLookupGetter) {
// https://tc39.github.io/ecma262/#sec-object.prototype.__lookupSetter__
BUILTIN(ObjectLookupSetter) {
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0);
Handle<Object> name = args.at<Object>(1);
Handle<Object> object = args.at(0);
Handle<Object> name = args.at(1);
return ObjectLookupAccessor(isolate, object, name, ACCESSOR_SETTER);
}
......@@ -790,7 +790,7 @@ BUILTIN(ObjectPrototypeSetProto) {
}
// 2. If Type(proto) is neither Object nor Null, return undefined.
Handle<Object> proto = args.at<Object>(1);
Handle<Object> proto = args.at(1);
if (!proto->IsNull(isolate) && !proto->IsJSReceiver()) {
return isolate->heap()->undefined_value();
}
......@@ -865,8 +865,8 @@ BUILTIN(ObjectGetOwnPropertySymbols) {
BUILTIN(ObjectIs) {
SealHandleScope shs(isolate);
DCHECK_EQ(3, args.length());
Handle<Object> value1 = args.at<Object>(1);
Handle<Object> value2 = args.at<Object>(2);
Handle<Object> value1 = args.at(1);
Handle<Object> value2 = args.at(2);
return isolate->heap()->ToBoolean(value1->SameValue(*value2));
}
......
......@@ -43,7 +43,7 @@ BUILTIN(CreateResolvingFunctions) {
DCHECK_EQ(3, args.length());
Handle<JSObject> promise = args.at<JSObject>(1);
Handle<Object> debug_event = args.at<Object>(2);
Handle<Object> debug_event = args.at(2);
Handle<JSFunction> resolve, reject;
PromiseUtils::CreateResolvingFunctions(isolate, promise, debug_event,
......
......@@ -17,9 +17,9 @@ namespace internal {
BUILTIN(ReflectDefineProperty) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> key = args.at<Object>(2);
Handle<Object> attributes = args.at<Object>(3);
Handle<Object> target = args.at(1);
Handle<Object> key = args.at(2);
Handle<Object> attributes = args.at(3);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -48,8 +48,8 @@ BUILTIN(ReflectDefineProperty) {
BUILTIN(ReflectDeleteProperty) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> key = args.at<Object>(2);
Handle<Object> target = args.at(1);
Handle<Object> key = args.at(2);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -73,7 +73,7 @@ BUILTIN(ReflectGet) {
HandleScope scope(isolate);
Handle<Object> target = args.atOrUndefined(isolate, 1);
Handle<Object> key = args.atOrUndefined(isolate, 2);
Handle<Object> receiver = args.length() > 3 ? args.at<Object>(3) : target;
Handle<Object> receiver = args.length() > 3 ? args.at(3) : target;
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -95,8 +95,8 @@ BUILTIN(ReflectGet) {
BUILTIN(ReflectGetOwnPropertyDescriptor) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> key = args.at<Object>(2);
Handle<Object> target = args.at(1);
Handle<Object> key = args.at(2);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -121,7 +121,7 @@ BUILTIN(ReflectGetOwnPropertyDescriptor) {
BUILTIN(ReflectGetPrototypeOf) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> target = args.at(1);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -138,8 +138,8 @@ BUILTIN(ReflectGetPrototypeOf) {
BUILTIN(ReflectHas) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> key = args.at<Object>(2);
Handle<Object> target = args.at(1);
Handle<Object> key = args.at(2);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -162,7 +162,7 @@ BUILTIN(ReflectHas) {
BUILTIN(ReflectIsExtensible) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> target = args.at(1);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -181,7 +181,7 @@ BUILTIN(ReflectIsExtensible) {
BUILTIN(ReflectOwnKeys) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> target = args.at(1);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -203,7 +203,7 @@ BUILTIN(ReflectOwnKeys) {
BUILTIN(ReflectPreventExtensions) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> target = args.at(1);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -224,7 +224,7 @@ BUILTIN(ReflectSet) {
Handle<Object> target = args.atOrUndefined(isolate, 1);
Handle<Object> key = args.atOrUndefined(isolate, 2);
Handle<Object> value = args.atOrUndefined(isolate, 3);
Handle<Object> receiver = args.length() > 4 ? args.at<Object>(4) : target;
Handle<Object> receiver = args.length() > 4 ? args.at(4) : target;
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......@@ -249,8 +249,8 @@ BUILTIN(ReflectSet) {
BUILTIN(ReflectSetPrototypeOf) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
Handle<Object> target = args.at<Object>(1);
Handle<Object> proto = args.at<Object>(2);
Handle<Object> target = args.at(1);
Handle<Object> proto = args.at(2);
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
......
......@@ -14,6 +14,46 @@ namespace internal {
typedef CodeStubAssembler::ResultMode ResultMode;
typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode;
class StringBuiltinsAssembler : public CodeStubAssembler {
public:
explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
Node* LoadOneByteChar(Node* string, Node* index) {
return Load(MachineType::Uint8(), string, OneByteCharOffset(index));
}
Node* OneByteCharAddress(Node* string, Node* index) {
Node* offset = OneByteCharOffset(index);
return IntPtrAdd(BitcastTaggedToWord(string), offset);
}
Node* OneByteCharOffset(Node* index) {
return CharOffset(String::ONE_BYTE_ENCODING, index);
}
Node* CharOffset(String::Encoding encoding, Node* index) {
const int header = SeqOneByteString::kHeaderSize - kHeapObjectTag;
Node* offset = index;
if (encoding == String::TWO_BYTE_ENCODING) {
offset = IntPtrAddFoldConstants(offset, offset);
}
offset = IntPtrAddFoldConstants(offset, IntPtrConstant(header));
return offset;
}
void BranchIfSimpleOneByteStringInstanceType(Node* instance_type,
Label* if_true,
Label* if_false) {
const int kMask = kStringRepresentationMask | kStringEncodingMask;
const int kType = kOneByteStringTag | kSeqStringTag;
Branch(Word32Equal(Word32And(instance_type, Int32Constant(kMask)),
Int32Constant(kType)),
if_true, if_false);
}
};
namespace {
void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
......@@ -567,7 +607,7 @@ bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) {
}
uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) {
Handle<Object> value = args.at<Object>(1 + index);
Handle<Object> value = args.at(1 + index);
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1);
if (!IsValidCodePoint(isolate, value)) {
isolate->Throw(*isolate->factory()->NewRangeError(
......@@ -831,13 +871,131 @@ BUILTIN(StringPrototypeIncludes) {
return *isolate->factory()->ToBoolean(index_in_str != -1);
}
// ES6 section 21.1.3.8 String.prototype.indexOf ( searchString [ , position ] )
BUILTIN(StringPrototypeIndexOf) {
HandleScope handle_scope(isolate);
// ES6 #sec-string.prototype.indexof
TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) {
Variable search_string(this, MachineRepresentation::kTagged),
position(this, MachineRepresentation::kTagged);
Label call_runtime(this), call_runtime_unchecked(this), argc_0(this),
no_argc_0(this), argc_1(this), no_argc_1(this), argc_2(this),
fast_path(this), return_minus_1(this);
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CodeStubArguments arguments(this, argc);
Node* receiver = arguments.GetReceiver();
// From now on use word-size argc value.
argc = arguments.GetLength();
GotoIf(IntPtrEqual(argc, IntPtrConstant(0)), &argc_0);
GotoIf(IntPtrEqual(argc, IntPtrConstant(1)), &argc_1);
Goto(&argc_2);
Bind(&argc_0);
{
Comment("0 Argument case");
Node* undefined = UndefinedConstant();
search_string.Bind(undefined);
position.Bind(undefined);
Goto(&call_runtime);
}
Bind(&argc_1);
{
Comment("1 Argument case");
search_string.Bind(arguments.AtIndex(0));
position.Bind(SmiConstant(0));
Goto(&fast_path);
}
Bind(&argc_2);
{
Comment("2 Argument case");
search_string.Bind(arguments.AtIndex(0));
position.Bind(arguments.AtIndex(1));
GotoUnless(TaggedIsSmi(position.value()), &call_runtime);
Goto(&fast_path);
}
Bind(&fast_path);
{
Comment("Fast Path");
Label zero_length_needle(this);
GotoIf(TaggedIsSmi(receiver), &call_runtime);
Node* needle = search_string.value();
GotoIf(TaggedIsSmi(needle), &call_runtime);
Node* instance_type = LoadInstanceType(receiver);
GotoUnless(IsStringInstanceType(instance_type), &call_runtime);
Node* needle_instance_type = LoadInstanceType(needle);
GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime);
// At this point we know that the receiver and the needle are Strings and
// that position is a Smi.
Node* needle_length = SmiUntag(LoadStringLength(needle));
// Use possibly faster runtime fallback for long search strings.
GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length),
&call_runtime_unchecked);
Node* string_length = SmiUntag(LoadStringLength(receiver));
Node* start_position = SmiUntag(position.value());
GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle);
// Check that the needle fits in the start position.
GotoUnless(IntPtrLessThanOrEqual(needle_length,
IntPtrSub(string_length, start_position)),
&return_minus_1);
// Only support one-byte strings on the fast path.
Label check_needle(this), continue_fast_path(this);
BranchIfSimpleOneByteStringInstanceType(instance_type, &check_needle,
&call_runtime_unchecked);
Bind(&check_needle);
BranchIfSimpleOneByteStringInstanceType(
needle_instance_type, &continue_fast_path, &call_runtime_unchecked);
Bind(&continue_fast_path);
{
Node* needle_byte =
ChangeInt32ToIntPtr(LoadOneByteChar(needle, IntPtrConstant(0)));
Node* start_address = OneByteCharAddress(receiver, start_position);
Node* search_length = IntPtrSub(string_length, start_position);
// Call out to the highly optimized memchr to perform the actual byte
// search.
Node* memchr =
ExternalConstant(ExternalReference::libc_memchr_function(isolate()));
Node* result_address =
CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
MachineType::IntPtr(), MachineType::UintPtr(), memchr,
start_address, needle_byte, search_length);
GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1);
Node* result_index =
IntPtrAdd(IntPtrSub(result_address, start_address), start_position);
arguments.PopAndReturn(SmiTag(result_index));
}
Bind(&zero_length_needle);
{
Comment("0-length needle");
arguments.PopAndReturn(SmiTag(IntPtrMin(string_length, start_position)));
}
}
return String::IndexOf(isolate, args.receiver(),
args.atOrUndefined(isolate, 1),
args.atOrUndefined(isolate, 2));
Bind(&return_minus_1);
{ arguments.PopAndReturn(SmiConstant(-1)); }
Bind(&call_runtime);
{
Comment("Call Runtime");
Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver,
search_string.value(), position.value());
arguments.PopAndReturn(result);
}
Bind(&call_runtime_unchecked);
{
// Simplified version of the runtime call where the types of the arguments
// are already known due to type checks in this stub.
Comment("Call Runtime Unchecked");
Node* result =
CallRuntime(Runtime::kStringIndexOfUnchecked, context, receiver,
search_string.value(), position.value());
arguments.PopAndReturn(result);
}
}
// ES6 section 21.1.3.9
......@@ -861,8 +1019,8 @@ BUILTIN(StringPrototypeLocaleCompare) {
TO_THIS_STRING(str1, "String.prototype.localeCompare");
Handle<String> str2;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, str2, Object::ToString(isolate, args.at<Object>(1)));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str2,
Object::ToString(isolate, args.at(1)));
if (str1.is_identical_to(str2)) return Smi::kZero; // Equal.
int str1_length = str1->length();
......
......@@ -30,7 +30,7 @@ class BuiltinArguments : public Arguments {
return Arguments::operator[](index);
}
template <class S>
template <class S = Object>
Handle<S> at(int index) {
DCHECK_LT(index, length());
return Arguments::at<S>(index);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -4380,6 +4380,11 @@ Node* CodeStubAssembler::IntPtrMax(Node* left, Node* right) {
MachineType::PointerRepresentation());
}
Node* CodeStubAssembler::IntPtrMin(Node* left, Node* right) {
return SelectConstant(IntPtrLessThanOrEqual(left, right), left, right,
MachineType::PointerRepresentation());
}
template <class Dictionary>
Node* CodeStubAssembler::GetNumberOfElements(Node* dictionary) {
return LoadFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex);
......
......@@ -139,7 +139,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IntPtrSubFoldConstants(Node* left, Node* right);
// Round the 32bits payload of the provided word up to the next power of two.
Node* IntPtrRoundUpToPowerOfTwo32(Node* value);
// Select the maximum of the two provided IntPtr values.
Node* IntPtrMax(Node* left, Node* right);
// Select the minimum of the two provided IntPtr values.
Node* IntPtrMin(Node* left, Node* right);
// Float64 operations.
Node* Float64Ceil(Node* x);
......
......@@ -546,6 +546,15 @@ Node* CodeAssembler::CallCFunction2(MachineType return_type,
function, arg0, arg1);
}
Node* CodeAssembler::CallCFunction3(MachineType return_type,
MachineType arg0_type,
MachineType arg1_type,
MachineType arg2_type, Node* function,
Node* arg0, Node* arg1, Node* arg2) {
return raw_assembler()->CallCFunction3(return_type, arg0_type, arg1_type,
arg2_type, function, arg0, arg1, arg2);
}
void CodeAssembler::Goto(Label* label) {
label->MergeVariables();
raw_assembler()->Goto(label->label_);
......@@ -718,12 +727,13 @@ void CodeAssemblerLabel::Bind() {
for (auto var : variable_phis_) {
CodeAssemblerVariable::Impl* var_impl = var.first;
auto i = variable_merges_.find(var_impl);
// If the following assert fires, then a variable that has been marked as
// If the following asserts fire, then a variable that has been marked as
// being merged at the label--either by explicitly marking it so in the
// label constructor or by having seen different bound values at branches
// into the label--doesn't have a bound value along all of the paths that
// have been merged into the label up to this point.
DCHECK(i != variable_merges_.end() && i->second.size() == merge_count_);
DCHECK(i != variable_merges_.end());
DCHECK_EQ(i->second.size(), merge_count_);
Node* phi = state_->raw_assembler_->Phi(
var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
variable_phis_[var_impl] = phi;
......
......@@ -163,6 +163,7 @@ typedef ZoneList<CodeAssemblerVariable*> CodeAssemblerVariableList;
V(Float64RoundTiesEven) \
V(Float64RoundTruncate) \
V(Word32Clz) \
V(Word32Not) \
V(Word32BinaryNot)
// A "public" interface used by components outside of compiler directory to
......@@ -354,6 +355,11 @@ class V8_EXPORT_PRIVATE CodeAssembler {
MachineType arg1_type, Node* function, Node* arg0,
Node* arg1);
// Call to a C function with three arguments.
Node* CallCFunction3(MachineType return_type, MachineType arg0_type,
MachineType arg1_type, MachineType arg2_type,
Node* function, Node* arg0, Node* arg1, Node* arg2);
// Exception handling support.
void GotoIfException(Node* node, Label* if_exception,
Variable* exception_var = nullptr);
......
......@@ -254,6 +254,21 @@ Node* RawMachineAssembler::CallCFunction2(MachineType return_type,
return AddNode(common()->Call(descriptor), function, arg0, arg1);
}
Node* RawMachineAssembler::CallCFunction3(MachineType return_type,
MachineType arg0_type,
MachineType arg1_type,
MachineType arg2_type, Node* function,
Node* arg0, Node* arg1, Node* arg2) {
MachineSignature::Builder builder(zone(), 1, 3);
builder.AddReturn(return_type);
builder.AddParam(arg0_type);
builder.AddParam(arg1_type);
builder.AddParam(arg2_type);
const CallDescriptor* descriptor =
Linkage::GetSimplifiedCDescriptor(zone(), builder.Build());
return AddNode(common()->Call(descriptor), function, arg0, arg1, arg2);
}
Node* RawMachineAssembler::CallCFunction8(
MachineType return_type, MachineType arg0_type, MachineType arg1_type,
......
......@@ -723,6 +723,10 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
Node* CallCFunction2(MachineType return_type, MachineType arg0_type,
MachineType arg1_type, Node* function, Node* arg0,
Node* arg1);
// Call to a C function with three arguments.
Node* CallCFunction3(MachineType return_type, MachineType arg0_type,
MachineType arg1_type, MachineType arg2_type,
Node* function, Node* arg0, Node* arg1, Node* arg2);
// Call to a C function with eight arguments.
Node* CallCFunction8(MachineType return_type, MachineType arg0_type,
MachineType arg1_type, MachineType arg2_type,
......
......@@ -3699,9 +3699,9 @@ MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
return array;
} else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
} else if (args->length() == 1 && args->at(0)->IsNumber()) {
uint32_t length;
if (!args->at<Object>(0)->ToArrayLength(&length)) {
if (!args->at(0)->ToArrayLength(&length)) {
return ThrowArrayLengthRangeError(array->GetIsolate());
}
......
......@@ -230,6 +230,8 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"f64_mod_wrapper");
Add(ExternalReference::wasm_call_trap_callback_for_testing(isolate).address(),
"wasm::call_trap_callback_for_testing");
Add(ExternalReference::libc_memchr_function(isolate).address(),
"libc_memchr");
Add(ExternalReference::log_enter_external_function(isolate).address(),
"Logger::EnterExternal");
Add(ExternalReference::log_leave_external_function(isolate).address(),
......
......@@ -2636,7 +2636,7 @@ RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> function = args.at<Object>(0);
Handle<Object> function = args.at(0);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
Handle<Smi> slot = args.at<Smi>(2);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
......@@ -2652,7 +2652,7 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> receiver = args.at<Object>(0);
Handle<Object> receiver = args.at(0);
Handle<Name> key = args.at<Name>(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
......@@ -2749,8 +2749,8 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> receiver = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
Handle<Object> receiver = args.at(0);
Handle<Object> key = args.at(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
......@@ -2765,8 +2765,8 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
HandleScope scope(isolate);
typedef LoadWithVectorDescriptor Descriptor;
DCHECK_EQ(Descriptor::kParameterCount, args.length());
Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver);
Handle<Object> key = args.at<Object>(Descriptor::kName);
Handle<Object> receiver = args.at(Descriptor::kReceiver);
Handle<Object> key = args.at(Descriptor::kName);
Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
Handle<TypeFeedbackVector> vector =
args.at<TypeFeedbackVector>(Descriptor::kVector);
......@@ -2783,10 +2783,10 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Object> receiver = args.at<Object>(3);
Handle<Object> receiver = args.at(3);
Handle<Name> key = args.at<Name>(4);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
......@@ -2810,11 +2810,11 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Object> receiver = args.at<Object>(3);
Handle<Object> key = args.at<Object>(4);
Handle<Object> receiver = args.at(3);
Handle<Object> key = args.at(4);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
KeyedStoreICNexus nexus(vector, vector_slot);
KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
......@@ -2827,10 +2827,10 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at<Object>(0);
Handle<Object> value = args.at(0);
// slot and vector parameters are not used.
Handle<Object> object = args.at<Object>(3);
Handle<Object> key = args.at<Object>(4);
Handle<Object> object = args.at(3);
Handle<Object> key = args.at(4);
LanguageMode language_mode;
KeyedStoreICNexus nexus(isolate);
KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
......@@ -2844,9 +2844,9 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
HandleScope scope(isolate);
// Runtime functions don't follow the IC's calling convention.
Handle<Object> object = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
Handle<Object> value = args.at<Object>(2);
Handle<Object> object = args.at(0);
Handle<Object> key = args.at(1);
Handle<Object> value = args.at(2);
Handle<Map> map = args.at<Map>(3);
LanguageMode language_mode;
KeyedStoreICNexus nexus(isolate);
......@@ -2995,8 +2995,8 @@ RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
typedef BinaryOpDescriptor Descriptor;
Handle<Object> left = args.at<Object>(Descriptor::kLeft);
Handle<Object> right = args.at<Object>(Descriptor::kRight);
Handle<Object> left = args.at(Descriptor::kLeft);
Handle<Object> right = args.at(Descriptor::kRight);
BinaryOpIC ic(isolate);
RETURN_RESULT_OR_FAILURE(
isolate, ic.Transition(Handle<AllocationSite>::null(), left, right));
......@@ -3009,8 +3009,8 @@ RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
typedef BinaryOpWithAllocationSiteDescriptor Descriptor;
Handle<AllocationSite> allocation_site =
args.at<AllocationSite>(Descriptor::kAllocationSite);
Handle<Object> left = args.at<Object>(Descriptor::kLeft);
Handle<Object> right = args.at<Object>(Descriptor::kRight);
Handle<Object> left = args.at(Descriptor::kLeft);
Handle<Object> right = args.at(Descriptor::kRight);
BinaryOpIC ic(isolate);
RETURN_RESULT_OR_FAILURE(isolate,
ic.Transition(allocation_site, left, right));
......@@ -3093,7 +3093,7 @@ RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
return ic.UpdateCaches(args.at(0), args.at(1));
}
......@@ -3116,7 +3116,7 @@ Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
DCHECK(args.length() == 1);
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0);
Handle<Object> object = args.at(0);
ToBooleanIC ic(isolate);
return *ic.ToBoolean(object);
}
......@@ -3127,7 +3127,7 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
Handle<JSObject> holder = args.at<JSObject>(1);
Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
Handle<Name> name = args.at<Name>(3);
Handle<Object> value = args.at<Object>(4);
Handle<Object> value = args.at(4);
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
HandleScope scope(isolate);
......@@ -3171,7 +3171,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
Handle<Name> name =
args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Handle<Object> receiver =
args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Handle<JSObject> holder =
args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
HandleScope scope(isolate);
......@@ -3207,7 +3207,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
Handle<Name> name =
args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Handle<Object> receiver =
args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Handle<JSObject> holder =
args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
......@@ -3263,7 +3263,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
Handle<JSObject> receiver = args.at<JSObject>(0);
Handle<Name> name = args.at<Name>(1);
Handle<Object> value = args.at<Object>(2);
Handle<Object> value = args.at(2);
DCHECK(receiver->HasNamedInterceptor());
InterceptorInfo* interceptor = receiver->GetNamedInterceptor();
......
......@@ -79,28 +79,16 @@ class MachineType {
return semantic() == MachineSemantic::kUint32 ||
semantic() == MachineSemantic::kUint64;
}
static MachineRepresentation PointerRepresentation() {
return (kPointerSize == 4) ? MachineRepresentation::kWord32
: MachineRepresentation::kWord64;
}
static MachineType Pointer() {
return MachineType(PointerRepresentation(), MachineSemantic::kNone);
static MachineType UintPtr() {
return (kPointerSize == 4) ? Uint32() : Uint64();
}
static MachineType IntPtr() {
return (kPointerSize == 4) ? Int32() : Int64();
}
static MachineType Float32() {
return MachineType(MachineRepresentation::kFloat32,
MachineSemantic::kNumber);
}
static MachineType Float64() {
return MachineType(MachineRepresentation::kFloat64,
MachineSemantic::kNumber);
}
static MachineType Simd128() {
return MachineType(MachineRepresentation::kSimd128, MachineSemantic::kNone);
}
static MachineType Int8() {
return MachineType(MachineRepresentation::kWord8, MachineSemantic::kInt32);
}
......@@ -128,6 +116,20 @@ class MachineType {
return MachineType(MachineRepresentation::kWord64,
MachineSemantic::kUint64);
}
static MachineType Float32() {
return MachineType(MachineRepresentation::kFloat32,
MachineSemantic::kNumber);
}
static MachineType Float64() {
return MachineType(MachineRepresentation::kFloat64,
MachineSemantic::kNumber);
}
static MachineType Simd128() {
return MachineType(MachineRepresentation::kSimd128, MachineSemantic::kNone);
}
static MachineType Pointer() {
return MachineType(PointerRepresentation(), MachineSemantic::kNone);
}
static MachineType TaggedPointer() {
return MachineType(MachineRepresentation::kTaggedPointer,
MachineSemantic::kAny);
......
......@@ -9919,6 +9919,7 @@ class String: public Name {
// returned structure will report so, and can't provide a vector of either
// kind.
FlatContent GetFlatContent();
FlatContent GetFlattenedContent();
// Returns the parent of a sliced string or first part of a flat cons string.
// Requires: StringShape(this).IsIndirect() && this->IsFlat()
......
......@@ -537,7 +537,7 @@ RUNTIME_FUNCTION(Runtime_ArrayIndexOf) {
CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
// Let O be ? ToObject(this value).
Handle<Object> receiver_obj = args.at<Object>(0);
Handle<Object> receiver_obj = args.at(0);
if (receiver_obj->IsNull(isolate) || receiver_obj->IsUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
......@@ -545,8 +545,8 @@ RUNTIME_FUNCTION(Runtime_ArrayIndexOf) {
"Array.prototype.indexOf")));
}
Handle<JSReceiver> object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, object, Object::ToObject(isolate, args.at<Object>(0)));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, object,
Object::ToObject(isolate, args.at(0)));
// Let len be ? ToLength(? Get(O, "length")).
int64_t len;
......
......@@ -454,7 +454,7 @@ RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
HandleScope scope(isolate);
DCHECK(args.length() == 6);
Handle<Object> callee = args.at<Object>(0);
Handle<Object> callee = args.at(0);
// If "eval" didn't refer to the original GlobalEval, it's not a
// direct call to eval.
......
......@@ -278,7 +278,7 @@ RUNTIME_FUNCTION(Runtime_Call) {
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
ScopedVector<Handle<Object>> argv(argc);
for (int i = 0; i < argc; ++i) {
argv[i] = args.at<Object>(2 + i);
argv[i] = args.at(2 + i);
}
RETURN_RESULT_OR_FAILURE(
isolate, Execution::Call(isolate, target, receiver, argc, argv.start()));
......
......@@ -106,9 +106,9 @@ RUNTIME_FUNCTION(Runtime_ThrowTypeError) {
CONVERT_SMI_ARG_CHECKED(message_id_smi, 0);
Handle<Object> undefined = isolate->factory()->undefined_value();
Handle<Object> arg0 = (args.length() > 1) ? args.at<Object>(1) : undefined;
Handle<Object> arg1 = (args.length() > 2) ? args.at<Object>(2) : undefined;
Handle<Object> arg2 = (args.length() > 3) ? args.at<Object>(3) : undefined;
Handle<Object> arg0 = (args.length() > 1) ? args.at(1) : undefined;
Handle<Object> arg1 = (args.length() > 2) ? args.at(2) : undefined;
Handle<Object> arg2 = (args.length() > 3) ? args.at(3) : undefined;
MessageTemplate::Template message_id =
static_cast<MessageTemplate::Template>(message_id_smi);
......
......@@ -133,7 +133,7 @@ Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
// ES6 19.1.3.2
RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
HandleScope scope(isolate);
Handle<Object> property = args.at<Object>(1);
Handle<Object> property = args.at(1);
Handle<Name> key;
uint32_t index;
......@@ -145,7 +145,7 @@ RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
key_is_array_index = key->AsArrayIndex(&index);
}
Handle<Object> object = args.at<Object>(0);
Handle<Object> object = args.at(0);
if (object->IsJSObject()) {
Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
......@@ -212,7 +212,7 @@ RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
// an Object.create stub.
RUNTIME_FUNCTION(Runtime_ObjectCreate) {
HandleScope scope(isolate);
Handle<Object> prototype = args.at<Object>(0);
Handle<Object> prototype = args.at(0);
if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype));
......@@ -262,7 +262,7 @@ RUNTIME_FUNCTION(Runtime_ObjectCreate) {
}
// Define the properties if properties was specified and is not undefined.
Handle<Object> properties = args.at<Object>(1);
Handle<Object> properties = args.at(1);
if (!properties->IsUndefined(isolate)) {
RETURN_FAILURE_ON_EXCEPTION(
isolate, JSReceiver::DefineProperties(isolate, object, properties));
......
......@@ -44,7 +44,7 @@ RUNTIME_FUNCTION(Runtime_JSProxyCall) {
// 6.a. Return Call(target, thisArgument, argumentsList).
ScopedVector<Handle<Object>> argv(arguments_length);
for (int i = 0; i < arguments_length; ++i) {
argv[i] = args.at<Object>(i + 1);
argv[i] = args.at(i + 1);
}
RETURN_RESULT_OR_FAILURE(
isolate, Execution::Call(isolate, target, receiver, arguments_length,
......@@ -100,7 +100,7 @@ RUNTIME_FUNCTION(Runtime_JSProxyConstruct) {
// 6.b. Return Construct(target, argumentsList, newTarget).
ScopedVector<Handle<Object>> argv(arguments_length);
for (int i = 0; i < arguments_length; ++i) {
argv[i] = args.at<Object>(i + 1);
argv[i] = args.at(i + 1);
}
RETURN_RESULT_OR_FAILURE(
isolate, Execution::New(isolate, target, new_target, arguments_length,
......
......@@ -1495,7 +1495,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, recv, 0);
CONVERT_ARG_HANDLE_CHECKED(String, string, 1);
Handle<Object> replace_obj = args.at<Object>(2);
Handle<Object> replace_obj = args.at(2);
Factory* factory = isolate->factory();
......
......@@ -171,7 +171,7 @@ RUNTIME_FUNCTION(Runtime_IsSimdValue) {
// TODO(gdeepti): Fix to use ToNumber conversion once polyfill is updated.
#define CONVERT_SIMD_LANE_ARG_CHECKED(name, index, lanes) \
Handle<Object> name_object = args.at<Object>(index); \
Handle<Object> name_object = args.at(index); \
if (!name_object->IsNumber()) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewTypeError(MessageTemplate::kInvalidSimdIndex)); \
......@@ -228,10 +228,10 @@ RUNTIME_FUNCTION(Runtime_IsSimdValue) {
// Common functions.
#define GET_NUMERIC_ARG(lane_type, name, index) \
Handle<Object> a; \
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \
isolate, a, Object::ToNumber(args.at<Object>(index))); \
#define GET_NUMERIC_ARG(lane_type, name, index) \
Handle<Object> a; \
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, a, \
Object::ToNumber(args.at(index))); \
name = ConvertNumber<lane_type>(a->Number());
#define GET_BOOLEAN_ARG(lane_type, name, index) \
......@@ -409,7 +409,7 @@ SIMD_MAXNUM_FUNCTION(Float32x4, float, 4)
FUNCTION(Uint8x16, uint8_t, 8, 16)
#define CONVERT_SHIFT_ARG_CHECKED(name, index) \
Handle<Object> name_object = args.at<Object>(index); \
Handle<Object> name_object = args.at(index); \
if (!name_object->IsNumber()) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewTypeError(MessageTemplate::kInvalidSimdOperation)); \
......@@ -880,16 +880,16 @@ SIMD_FROM_BITS_TYPES(SIMD_FROM_BITS_FUNCTION)
FUNCTION(Int32x4, int32_t, 4) \
FUNCTION(Uint32x4, uint32_t, 4)
#define SIMD_COERCE_INDEX(name, i) \
Handle<Object> length_object, number_object; \
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \
isolate, length_object, Object::ToLength(isolate, args.at<Object>(i))); \
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_object, \
Object::ToNumber(args.at<Object>(i))); \
if (number_object->Number() != length_object->Number()) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewTypeError(MessageTemplate::kInvalidSimdIndex)); \
} \
#define SIMD_COERCE_INDEX(name, i) \
Handle<Object> length_object, number_object; \
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, length_object, \
Object::ToLength(isolate, args.at(i))); \
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_object, \
Object::ToNumber(args.at(i))); \
if (number_object->Number() != length_object->Number()) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewTypeError(MessageTemplate::kInvalidSimdIndex)); \
} \
int32_t name = number_object->Number();
// Common Load and Store Functions
......
......@@ -86,17 +86,32 @@ RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
return isolate->StackOverflow();
}
// ES6 #sec-string.prototype.indexof
// String.prototype.indexOf(searchString [, position])
RUNTIME_FUNCTION(Runtime_StringIndexOf) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
return String::IndexOf(isolate, args.at<Object>(0), args.at<Object>(1),
args.at<Object>(2));
return String::IndexOf(isolate, args.at(0), args.at(1), args.at(2));
}
// ES6 #sec-string.prototype.indexof
// String.prototype.indexOf(searchString, position)
// Fast version that assumes that does not perform conversions of the incoming
// arguments.
RUNTIME_FUNCTION(Runtime_StringIndexOfUnchecked) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
Handle<String> receiver_string = args.at<String>(0);
Handle<String> search_string = args.at<String>(1);
int index = std::min(std::max(args.smi_at(2), 0), receiver_string->length());
return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string,
static_cast<uint32_t>(index)));
}
RUNTIME_FUNCTION(Runtime_StringLastIndexOf) {
HandleScope handle_scope(isolate);
return String::LastIndexOf(isolate, args.at<Object>(0), args.at<Object>(1),
return String::LastIndexOf(isolate, args.at(0), args.at(1),
isolate->factory()->undefined_value());
}
......
......@@ -24,7 +24,7 @@ namespace internal {
#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \
CHECK(args[index]->IsNumber()); \
Handle<Object> name = args.at<Object>(index);
Handle<Object> name = args.at(index);
// Cast the given object to a boolean and store it in a variable with
// the given name. If the object is not a boolean we crash safely.
......@@ -47,10 +47,10 @@ namespace internal {
// Cast the given argument to a size_t and store its value in a variable with
// the given name. If the argument is not a size_t we crash safely.
#define CONVERT_SIZE_ARG_CHECKED(name, index) \
CHECK(args[index]->IsNumber()); \
Handle<Object> name##_object = args.at<Object>(index); \
size_t name = 0; \
#define CONVERT_SIZE_ARG_CHECKED(name, index) \
CHECK(args[index]->IsNumber()); \
Handle<Object> name##_object = args.at(index); \
size_t name = 0; \
CHECK(TryNumberToSize(*name##_object, &name));
// Call the specified converter on the object *comand store the result in
......
......@@ -817,6 +817,7 @@ namespace internal {
#define FOR_EACH_INTRINSIC_STRINGS(F) \
F(StringReplaceOneCharWithString, 3, 1) \
F(StringIndexOf, 3, 1) \
F(StringIndexOfUnchecked, 3, 1) \
F(StringLastIndexOf, 2, 1) \
F(SubString, 3, 1) \
F(StringAdd, 2, 1) \
......
......@@ -583,7 +583,6 @@ class InitializedHandleScope {
std::unique_ptr<InitializedHandleScopeImpl> initialized_handle_scope_impl_;
};
class HandleAndZoneScope : public InitializedHandleScope {
public:
HandleAndZoneScope();
......@@ -597,4 +596,18 @@ class HandleAndZoneScope : public InitializedHandleScope {
std::unique_ptr<i::Zone> main_zone_;
};
class StaticOneByteResource : public v8::String::ExternalOneByteStringResource {
public:
explicit StaticOneByteResource(const char* data) : data_(data) {}
~StaticOneByteResource() {}
const char* data() const { return data_; }
size_t length() const { return strlen(data_); }
private:
const char* data_;
};
#endif // ifndef CCTEST_H_
......@@ -1608,3 +1608,38 @@ TEST(Regress609831) {
CHECK(v8::Utils::OpenHandle(*result)->IsSeqTwoByteString());
}
}
TEST(ExternalStringIndexOf) {
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(CcTest::isolate());
const char* raw_string = "abcdefghijklmnopqrstuvwxyz";
v8::Local<v8::String> string =
v8::String::NewExternalOneByte(CcTest::isolate(),
new StaticOneByteResource(raw_string))
.ToLocalChecked();
v8::Local<v8::Object> global = context->Global();
global->Set(context.local(), v8_str("external"), string).FromJust();
char source[] = "external.indexOf('%')";
for (size_t i = 0; i < strlen(raw_string); i++) {
source[18] = raw_string[i];
int result_position = static_cast<int>(i);
CHECK_EQ(result_position,
CompileRun(source)->Int32Value(context.local()).FromJust());
}
CHECK_EQ(-1,
CompileRun("external.indexOf('abcdefghijklmnopqrstuvwxyz%%%%%%')")
->Int32Value(context.local())
.FromJust());
CHECK_EQ(1, CompileRun("external.indexOf('', 1)")
->Int32Value(context.local())
.FromJust());
CHECK_EQ(-1, CompileRun("external.indexOf('a', 1)")
->Int32Value(context.local())
.FromJust());
CHECK_EQ(-1, CompileRun("external.indexOf('$')")
->Int32Value(context.local())
.FromJust());
}
......@@ -137,3 +137,60 @@ for (var lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) {
assertEquals(index, allCharsString.indexOf(pattern));
}
}
(function nonStringReceivers() {
let indexOf = String.prototype.indexOf;
assertThrows(() => indexOf.call(null), TypeError);
assertThrows(() => indexOf.call(undefined), TypeError);
assertEquals(-1, indexOf.call(1));
assertEquals(0, indexOf.call(1, "1"));
assertEquals(-1, indexOf.call(1.2));
assertEquals(0, indexOf.call(1.2, "1"));
assertEquals(1, indexOf.call(1.2, "."));
assertEquals(2, indexOf.call(1.2, "2"));
assertEquals(-1, indexOf.call(1.2, "1", 2));
assertEquals(-1, indexOf.call({}));
assertEquals(0, indexOf.call({}, "[object Object]"));
assertEquals(-1, indexOf.call({}, "[object", 1));
assertEquals(-1, indexOf.call([]));
assertEquals(0, indexOf.call([1,2], "1,2"));
assertEquals(-1, indexOf.call(this));
})();
(function nonStringSearchString() {
assertEquals(-1, "".indexOf(1));
assertEquals(2, "_0123".indexOf(1));
assertEquals(-1, "".indexOf(1.2));
assertEquals(1, "01.2".indexOf(1.2));
assertEquals(1, "01.2".indexOf(1.2, 1));
assertEquals(-1, "01.2".indexOf(1.2, 2));
assertEquals(-1, "".indexOf(null));
assertEquals(0, "null".indexOf(null));
assertEquals(-1, "".indexOf(undefined));
assertEquals(1, "_undefined_".indexOf(undefined));
assertEquals(0, "".indexOf([]));
assertEquals(0, "123".indexOf([]));
assertEquals(2, "1,2,3".indexOf([2,3]));
assertEquals(-1, "".indexOf({}));
assertEquals(-1, "".indexOf(this));
})();
(function nonStringPosition() {
assertEquals(0, "aba".indexOf("a", false));
assertEquals(2, "aba".indexOf("a", true));
assertEquals(2, "aba".indexOf("a", "1"));
assertEquals(2, "aba".indexOf("a", "1.00000"));
assertEquals(2, "aba".indexOf("a", "2.00000"));
assertEquals(-1, "aba".indexOf("a", "3.00000"));
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment