Commit e4d25389 authored by Benedikt Meurer's avatar Benedikt Meurer

[es6] Correct Function.prototype.apply, Reflect.construct and Reflect.apply.

Introduce a new Apply builtin that forms a correct and optimizable
foundation for the Function.prototype.apply, Reflect.construct and
Reflect.apply builtins (which properly does the PrepareForTailCall
as required by the ES2015 spec).

The new Apply builtin avoids going to the runtime if it is safe to
just access the backing store elements of the argArray, i.e. if you
pass a JSArray with no holes, or an unmapped, unmodified sloppy or
strict arguments object.

mips/mips64 ports by Balazs Kilvady <balazs.kilvady@imgtec.com>

CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_chromium_rel_ng;tryserver.blink:linux_blink_rel
BUG=v8:4413, v8:4430
LOG=n
R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/1523753002 .

Cr-Commit-Position: refs/heads/master@{#32927}
parent aafc3e54
This diff is collapsed.
This diff is collapsed.
......@@ -1865,11 +1865,8 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
Handle<JSFunction> apply = InstallFunction(
container, "reflect_apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), Builtins::kReflectApply);
apply->shared()->set_internal_formal_parameter_count(3);
apply->shared()->DontAdaptArguments();
apply->shared()->set_length(3);
Handle<TypeFeedbackVector> feedback_vector =
TypeFeedbackVector::CreatePushAppliedArgumentsVector(isolate);
apply->shared()->set_feedback_vector(*feedback_vector);
native_context->set_reflect_apply(*apply);
}
......@@ -1877,11 +1874,8 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
Handle<JSFunction> construct = InstallFunction(
container, "reflect_construct", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), Builtins::kReflectConstruct);
construct->shared()->set_internal_formal_parameter_count(3);
construct->shared()->DontAdaptArguments();
construct->shared()->set_length(2);
Handle<TypeFeedbackVector> feedback_vector =
TypeFeedbackVector::CreatePushAppliedArgumentsVector(isolate);
construct->shared()->set_feedback_vector(*feedback_vector);
native_context->set_reflect_construct(*construct);
}
......@@ -2535,22 +2529,17 @@ bool Genesis::InstallNatives(ContextType context_type) {
Handle<JSFunction> apply =
InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), Builtins::kFunctionApply);
Handle<TypeFeedbackVector> feedback_vector =
TypeFeedbackVector::CreatePushAppliedArgumentsVector(isolate());
apply->shared()->set_feedback_vector(*feedback_vector);
// Make sure that Function.prototype.call appears to be compiled.
// The code will never be called, but inline caching for call will
// only work if it appears to be compiled.
apply->shared()->DontAdaptArguments();
call->shared()->DontAdaptArguments();
DCHECK(call->is_compiled());
// Set the expected parameters for apply to 2; required by builtin.
apply->shared()->set_internal_formal_parameter_count(2);
// Set the lengths for the functions to satisfy ECMA-262.
call->shared()->set_length(1);
apply->shared()->set_length(2);
call->shared()->set_length(1);
}
// Set up the Promise constructor.
......
......@@ -116,6 +116,8 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(ConstructProxy, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(Construct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(Apply, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(HandleFastApiCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(InOptimizationQueue, BUILTIN, UNINITIALIZED, kNoExtraICState) \
......@@ -315,6 +317,8 @@ class Builtins {
static void Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm);
static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
static void Generate_Apply(MacroAssembler* masm);
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
static void Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode);
......
......@@ -91,14 +91,9 @@ enum BindingFlags {
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable)
#define NATIVE_CONTEXT_JS_BUILTINS(V) \
V(APPLY_PREPARE_BUILTIN_INDEX, JSFunction, apply_prepare_builtin) \
V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction, \
concat_iterable_to_array_builtin) \
V(REFLECT_APPLY_PREPARE_BUILTIN_INDEX, JSFunction, \
reflect_apply_prepare_builtin) \
V(REFLECT_CONSTRUCT_PREPARE_BUILTIN_INDEX, JSFunction, \
reflect_construct_prepare_builtin)
#define NATIVE_CONTEXT_JS_BUILTINS(V) \
V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction, \
concat_iterable_to_array_builtin)
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
......
This diff is collapsed.
......@@ -34,127 +34,6 @@ utils.Import(function(from) {
-----------------------------
*/
function APPLY_PREPARE(args) {
var length;
// First check that the receiver is callable.
if (!IS_CALLABLE(this)) {
throw %make_type_error(kApplyNonFunction, TO_STRING(this), typeof this);
}
// First check whether length is a positive Smi and args is an
// array. This is the fast case. If this fails, we do the slow case
// that takes care of more eventualities.
if (IS_ARRAY(args)) {
length = args.length;
if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
return length;
}
}
length = (args == null) ? 0 : TO_UINT32(args.length);
// We can handle any number of apply arguments if the stack is
// big enough, but sanity check the value to avoid overflow when
// multiplying with pointer size.
if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
// Make sure the arguments list has the right type.
if (args != null && !IS_SPEC_OBJECT(args)) {
throw %make_type_error(kWrongArgs, "Function.prototype.apply");
}
// Return the length which is the number of arguments to copy to the
// stack. It is guaranteed to be a small integer at this point.
return length;
}
function REFLECT_APPLY_PREPARE(args) {
var length;
// First check that the receiver is callable.
if (!IS_CALLABLE(this)) {
throw %make_type_error(kApplyNonFunction, TO_STRING(this), typeof this);
}
// First check whether length is a positive Smi and args is an
// array. This is the fast case. If this fails, we do the slow case
// that takes care of more eventualities.
if (IS_ARRAY(args)) {
length = args.length;
if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength) {
return length;
}
}
if (!IS_SPEC_OBJECT(args)) {
throw %make_type_error(kWrongArgs, "Reflect.apply");
}
length = TO_LENGTH(args.length);
// We can handle any number of apply arguments if the stack is
// big enough, but sanity check the value to avoid overflow when
// multiplying with pointer size.
if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
// Return the length which is the number of arguments to copy to the
// stack. It is guaranteed to be a small integer at this point.
return length;
}
function REFLECT_CONSTRUCT_PREPARE(
args, newTarget) {
var length;
var ctorOk = IS_CALLABLE(this) && %IsConstructor(this);
var newTargetOk = IS_CALLABLE(newTarget) && %IsConstructor(newTarget);
// First check whether length is a positive Smi and args is an
// array. This is the fast case. If this fails, we do the slow case
// that takes care of more eventualities.
if (IS_ARRAY(args)) {
length = args.length;
if (%_IsSmi(length) && length >= 0 && length < kSafeArgumentsLength &&
ctorOk && newTargetOk) {
return length;
}
}
if (!ctorOk) {
if (!IS_CALLABLE(this)) {
throw %make_type_error(kCalledNonCallable, TO_STRING(this));
} else {
throw %make_type_error(kNotConstructor, TO_STRING(this));
}
}
if (!newTargetOk) {
if (!IS_CALLABLE(newTarget)) {
throw %make_type_error(kCalledNonCallable, TO_STRING(newTarget));
} else {
throw %make_type_error(kNotConstructor, TO_STRING(newTarget));
}
}
if (!IS_SPEC_OBJECT(args)) {
throw %make_type_error(kWrongArgs, "Reflect.construct");
}
length = TO_LENGTH(args.length);
// We can handle any number of apply arguments if the stack is
// big enough, but sanity check the value to avoid overflow when
// multiplying with pointer size.
if (length > kSafeArgumentsLength) throw %make_range_error(kStackOverflow);
// Return the length which is the number of arguments to copy to the
// stack. It is guaranteed to be a small integer at this point.
return length;
}
function CONCAT_ITERABLE_TO_ARRAY(iterable) {
return %concat_iterable_to_array(this, iterable);
};
......@@ -261,10 +140,7 @@ utils.Export(function(to) {
});
%InstallToContext([
"apply_prepare_builtin", APPLY_PREPARE,
"concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
"reflect_apply_prepare_builtin", REFLECT_APPLY_PREPARE,
"reflect_construct_prepare_builtin", REFLECT_CONSTRUCT_PREPARE,
]);
%InstallToContext([
......
This diff is collapsed.
This diff is collapsed.
......@@ -672,6 +672,72 @@ MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
}
// static
MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
// 1. ReturnIfAbrupt(object).
// 2. (default elementTypes -- not applicable.)
// 3. If Type(obj) is not Object, throw a TypeError exception.
if (!object->IsJSReceiver()) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kCalledOnNonObject,
isolate->factory()->NewStringFromAsciiChecked(
"CreateListFromArrayLike")),
FixedArray);
}
// 4. Let len be ? ToLength(? Get(obj, "length")).
Handle<Object> raw_length_obj;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, raw_length_obj,
JSReceiver::GetProperty(object, isolate->factory()->length_string()),
FixedArray);
Handle<Object> raw_length_number;
ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
Object::ToLength(isolate, raw_length_obj),
FixedArray);
uint32_t len;
if (!raw_length_number->ToUint32(&len) ||
len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kInvalidArrayLength),
FixedArray);
}
// 5. Let list be an empty List.
Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
// 6. Let index be 0.
// 7. Repeat while index < len:
for (uint32_t index = 0; index < len; ++index) {
// 7a. Let indexName be ToString(index).
// 7b. Let next be ? Get(obj, indexName).
Handle<Object> next;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, next, Object::GetElement(isolate, object, index), FixedArray);
switch (element_types) {
case ElementTypes::kAll:
// Nothing to do.
break;
case ElementTypes::kStringAndSymbol: {
// 7c. If Type(next) is not an element of elementTypes, throw a
// TypeError exception.
if (!next->IsName()) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kNotPropertyName, next),
FixedArray);
}
// 7d. Append next as the last element of list.
// Internalize on the fly so we can use pointer identity later.
next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
break;
}
}
list->set(index, *next);
// 7e. Set index to index + 1. (See loop header.)
}
// 8. Return list.
return list;
}
// static
Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
......@@ -8470,64 +8536,6 @@ Maybe<bool> JSProxy::Enumerate(Isolate* isolate, Handle<JSReceiver> receiver,
}
// ES6 7.3.17 for elementTypes = (String, Symbol)
static MaybeHandle<FixedArray> CreateListFromArrayLike_StringSymbol(
Isolate* isolate, Handle<Object> object) {
// 1. ReturnIfAbrupt(object).
// 2. (default elementTypes -- not applicable.)
// 3. If Type(obj) is not Object, throw a TypeError exception.
if (!object->IsJSReceiver()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kCalledOnNonObject,
isolate->factory()->NewStringFromAsciiChecked(
"CreateListFromArrayLike")));
return MaybeHandle<FixedArray>();
}
// 4. Let len be ? ToLength(? Get(obj, "length")).
Handle<Object> raw_length_obj;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, raw_length_obj,
JSReceiver::GetProperty(object, isolate->factory()->length_string()),
FixedArray);
Handle<Object> raw_length_number;
ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
Object::ToLength(isolate, raw_length_obj),
FixedArray);
uint32_t len;
if (!raw_length_number->ToUint32(&len) ||
len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
isolate->Throw(*isolate->factory()->NewRangeError(
MessageTemplate::kInvalidArrayLength));
return MaybeHandle<FixedArray>();
}
// 5. Let list be an empty List.
Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
// 6. Let index be 0.
// 7. Repeat while index < len:
for (uint32_t index = 0; index < len; ++index) {
// 7a. Let indexName be ToString(index).
// 7b. Let next be ? Get(obj, indexName).
Handle<Object> next;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, next, Object::GetElement(isolate, object, index), FixedArray);
// 7c. If Type(next) is not an element of elementTypes, throw a
// TypeError exception.
if (!next->IsName()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kNotPropertyName, next));
return MaybeHandle<FixedArray>();
}
// 7d. Append next as the last element of list.
// Internalize on the fly so we can use pointer identity later.
next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
list->set(index, *next);
// 7e. Set index to index + 1. (See loop header.)
}
// 8. Return list.
return list;
}
// ES6 9.5.12
// Returns |true| on success, |nothing| in case of exception.
// static
......@@ -8572,7 +8580,8 @@ Maybe<bool> JSProxy::OwnPropertyKeys(Isolate* isolate,
Handle<FixedArray> trap_result;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, trap_result,
CreateListFromArrayLike_StringSymbol(isolate, trap_result_array),
Object::CreateListFromArrayLike(isolate, trap_result_array,
ElementTypes::kStringAndSymbol),
Nothing<bool>());
// 9. Let extensibleTarget be ? IsExtensible(target).
Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
......
......@@ -992,6 +992,9 @@ template <class C> inline bool Is(Object* obj);
V(WeakHashTable) \
V(OrderedHashTable)
// The element types selection for CreateListFromArrayLike.
enum class ElementTypes { kAll, kStringAndSymbol };
// Object is the abstract superclass for all classes in the
// object hierarchy.
// Object does not use any virtual functions to avoid the
......@@ -1165,6 +1168,10 @@ class Object {
MUST_USE_RESULT static MaybeHandle<Object> GetMethod(
Handle<JSReceiver> receiver, Handle<Name> name);
// ES6 section 7.3.17 CreateListFromArrayLike
MUST_USE_RESULT static MaybeHandle<FixedArray> CreateListFromArrayLike(
Isolate* isolate, Handle<Object> object, ElementTypes element_types);
// Check whether |object| is an instance of Error or NativeError.
static bool IsErrorObject(Isolate* isolate, Handle<Object> object);
......
......@@ -92,7 +92,7 @@ RUNTIME_FUNCTION(Runtime_ReThrow) {
RUNTIME_FUNCTION(Runtime_ThrowStackOverflow) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
DCHECK_LE(0, args.length());
return isolate->StackOverflow();
}
......@@ -179,6 +179,16 @@ RUNTIME_FUNCTION(Runtime_ThrowStrongModeImplicitConversion) {
}
RUNTIME_FUNCTION(Runtime_ThrowApplyNonFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
Handle<String> type = Object::TypeOf(isolate, object);
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kApplyNonFunction, object, type));
}
RUNTIME_FUNCTION(Runtime_PromiseRejectEvent) {
DCHECK(args.length() == 3);
HandleScope scope(isolate);
......@@ -437,5 +447,18 @@ RUNTIME_FUNCTION(Runtime_ThrowConstructedNonConstructable) {
isolate, NewTypeError(MessageTemplate::kNotConstructor, callsite));
}
// ES6 section 7.3.17 CreateListFromArrayLike (obj)
RUNTIME_FUNCTION(Runtime_CreateListFromArrayLike) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
Handle<FixedArray> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
Object::CreateListFromArrayLike(isolate, object, ElementTypes::kAll));
return *result;
}
} // namespace internal
} // namespace v8
......@@ -319,6 +319,7 @@ namespace internal {
F(UnwindAndFindExceptionHandler, 0, 1) \
F(PromoteScheduledException, 0, 1) \
F(ThrowReferenceError, 1, 1) \
F(ThrowApplyNonFunction, 1, 1) \
F(NewTypeError, 2, 1) \
F(NewSyntaxError, 2, 1) \
F(NewReferenceError, 2, 1) \
......@@ -349,7 +350,8 @@ namespace internal {
F(IS_VAR, 1, 1) \
F(IncrementStatsCounter, 1, 1) \
F(ThrowConstructedNonConstructable, 1, 1) \
F(ThrowCalledNonCallable, 1, 1)
F(ThrowCalledNonCallable, 1, 1) \
F(CreateListFromArrayLike, 1, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \
......
......@@ -159,28 +159,6 @@ int TypeFeedbackVector::GetIndexFromSpec(const FeedbackVectorSpec* spec,
}
// static
int TypeFeedbackVector::PushAppliedArgumentsIndex() {
return kReservedIndexCount;
}
// static
Handle<TypeFeedbackVector> TypeFeedbackVector::CreatePushAppliedArgumentsVector(
Isolate* isolate) {
StaticFeedbackVectorSpec spec;
FeedbackVectorSlot slot = spec.AddKeyedLoadICSlot();
// TODO(ishell): allocate this metadata only once.
Handle<TypeFeedbackMetadata> feedback_metadata =
TypeFeedbackMetadata::New(isolate, &spec);
Handle<TypeFeedbackVector> feedback_vector =
TypeFeedbackVector::New(isolate, feedback_metadata);
DCHECK_EQ(PushAppliedArgumentsIndex(), feedback_vector->GetIndex(slot));
USE(slot);
return feedback_vector;
}
// static
Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
Isolate* isolate, Handle<TypeFeedbackVector> vector) {
......
......@@ -254,10 +254,6 @@ class TypeFeedbackVector : public FixedArray {
return FeedbackVectorSlot(dummyIndex);
}
static int PushAppliedArgumentsIndex();
static Handle<TypeFeedbackVector> CreatePushAppliedArgumentsVector(
Isolate* isolate);
private:
void ClearSlotsImpl(SharedFunctionInfo* shared, bool force_clear);
......
This diff is collapsed.
......@@ -3678,39 +3678,6 @@ static void CheckVectorICCleared(Handle<JSFunction> f, int slot_index) {
}
TEST(ICInBuiltInIsClearedAppropriately) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Handle<JSFunction> apply;
{
LocalContext env;
v8::Local<v8::Value> res = CompileRun("Function.apply");
i::Handle<JSReceiver> maybe_apply =
v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(res));
apply = i::Handle<JSFunction>::cast(maybe_apply);
i::Handle<TypeFeedbackVector> vector(apply->shared()->feedback_vector());
FeedbackVectorHelper feedback_helper(vector);
CHECK_EQ(1, feedback_helper.slot_count());
CheckVectorIC(apply, 0, UNINITIALIZED);
CompileRun(
"function b(a1, a2, a3) { return a1 + a2 + a3; }"
"function fun(bar) { bar.apply({}, [1, 2, 3]); };"
"fun(b); fun(b)");
CheckVectorIC(apply, 0, MONOMORPHIC);
}
// Fire context dispose notification.
CcTest::isolate()->ContextDisposedNotification();
SimulateIncrementalMarking(CcTest::heap());
CcTest::heap()->CollectAllGarbage();
// The IC in apply has been cleared, ready to learn again.
CheckVectorIC(apply, 0, PREMONOMORPHIC);
}
TEST(IncrementalMarkingPreservesMonomorphicConstructor) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
......
......@@ -114,7 +114,7 @@ function al() {
return arguments.length + arguments[arguments.length - 1];
}
for (var j = 1; j < 0x40000000; j <<= 1) {
for (var j = 1; j < 0x4000000; j <<= 1) {
try {
var a = %NormalizeElements([]);
a.length = j;
......@@ -122,7 +122,7 @@ for (var j = 1; j < 0x40000000; j <<= 1) {
assertEquals(42 + j, al.apply(345, a));
} catch (e) {
assertTrue(e.toString().indexOf("Maximum call stack size exceeded") != -1);
for (; j < 0x40000000; j <<= 1) {
for (; j < 0x4000000; j <<= 1) {
var caught = false;
try {
a = %NormalizeElements([]);
......
......@@ -57,6 +57,18 @@ test(function() {
Object.defineProperty(1, "x", {});
}, "Object.defineProperty called on non-object", TypeError);
test(function() {
(function() {}).apply({}, 1);
}, "CreateListFromArrayLike called on non-object", TypeError);
test(function() {
Reflect.apply(function() {}, {}, 1);
}, "CreateListFromArrayLike called on non-object", TypeError);
test(function() {
Reflect.construct(function() {}, 1);
}, "CreateListFromArrayLike called on non-object", TypeError);
// kCalledOnNullOrUndefined
test(function() {
Array.prototype.shift.call(null);
......@@ -330,19 +342,6 @@ test(function() {
}, "Invalid property descriptor. Cannot both specify accessors " +
"and a value or writable attribute, #<Object>", TypeError);
// kWrongArgs
test(function() {
(function() {}).apply({}, 1);
}, "Function.prototype.apply: Arguments list has wrong type", TypeError);
test(function() {
Reflect.apply(function() {}, {}, 1);
}, "Reflect.apply: Arguments list has wrong type", TypeError);
test(function() {
Reflect.construct(function() {}, 1);
}, "Reflect.construct: Arguments list has wrong type", TypeError);
// === SyntaxError ===
......
......@@ -56,9 +56,9 @@ PASS arrayApplyChangeLength4() is 0
PASS var a = []; a.length = 0xFFFE; [].constructor.apply('', a).length is 0xFFFE
PASS var a = []; a.length = 0xFFFF; [].constructor.apply('', a).length is 0xFFFF
PASS var a = []; a.length = 0x10000; [].constructor.apply('', a).length is 0x10000
FAIL var a = []; a.length = 0x10001; [].constructor.apply('', a).length should throw an exception. Was 65537.
PASS var a = []; a.length = 0xFFFFFFFE; [].constructor.apply('', a).length threw exception RangeError: Maximum call stack size exceeded.
PASS var a = []; a.length = 0xFFFFFFFF; [].constructor.apply('', a).length threw exception RangeError: Maximum call stack size exceeded.
PASS var a = []; a.length = 0x10001; [].constructor.apply('', a).length is 0x10001
PASS var a = []; a.length = 0xFFFFFFFE; [].constructor.apply('', a).length threw exception RangeError: Invalid array length.
PASS var a = []; a.length = 0xFFFFFFFF; [].constructor.apply('', a).length threw exception RangeError: Invalid array length.
PASS (function(a,b,c,d){ return d ? -1 : (a+b+c); }).apply(undefined, {length:3, 0:100, 1:20, 2:3}) is 123
PASS successfullyParsed is true
......
......@@ -310,7 +310,7 @@ shouldBe("arrayApplyChangeLength4()", "0");
shouldBe("var a = []; a.length = 0xFFFE; [].constructor.apply('', a).length", "0xFFFE");
shouldBe("var a = []; a.length = 0xFFFF; [].constructor.apply('', a).length", "0xFFFF");
shouldBe("var a = []; a.length = 0x10000; [].constructor.apply('', a).length", "0x10000");
shouldThrow("var a = []; a.length = 0x10001; [].constructor.apply('', a).length");
shouldBe("var a = []; a.length = 0x10001; [].constructor.apply('', a).length", "0x10001");
shouldThrow("var a = []; a.length = 0xFFFFFFFE; [].constructor.apply('', a).length");
shouldThrow("var a = []; a.length = 0xFFFFFFFF; [].constructor.apply('', a).length");
......
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