Strict mode "this" transformation in Function.call/Function.apply.
In strict mode the transformation of "this" is skipped. Code review feedback. Testing memory operand against 8 bit IMM on ia32 and x64. Review URL: http://codereview.chromium.org/6524006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6799 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
ae8c5defbc
commit
582cf097e9
@ -1231,6 +1231,14 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
// Change context eagerly in case we need the global receiver.
|
||||
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
__ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
|
||||
__ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
|
||||
kSmiTagSize)));
|
||||
__ b(ne, &shift_arguments);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ ldr(r2, MemOperand(r2, -kPointerSize));
|
||||
// r0: actual number of arguments
|
||||
@ -1394,10 +1402,20 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
// Change context eagerly to get the right global object if necessary.
|
||||
__ ldr(r0, MemOperand(fp, kFunctionOffset));
|
||||
__ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
|
||||
// Load the shared function info while the function is still in r0.
|
||||
__ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
|
||||
|
||||
// Compute the receiver.
|
||||
Label call_to_object, use_global_receiver, push_receiver;
|
||||
__ ldr(r0, MemOperand(fp, kRecvOffset));
|
||||
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
__ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
|
||||
__ tst(r1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
|
||||
kSmiTagSize)));
|
||||
__ b(ne, &push_receiver);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ tst(r0, Operand(kSmiTagMask));
|
||||
__ b(eq, &call_to_object);
|
||||
__ LoadRoot(r1, Heap::kNullValueRootIndex);
|
||||
|
@ -589,6 +589,13 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
// Change context eagerly in case we need the global receiver.
|
||||
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
|
||||
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
__ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
|
||||
1 << SharedFunctionInfo::kStrictModeBitWithinByte);
|
||||
__ j(not_equal, &shift_arguments);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
|
||||
__ test(ebx, Immediate(kSmiTagMask));
|
||||
__ j(zero, &convert_to_object);
|
||||
@ -736,6 +743,14 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
// Compute the receiver.
|
||||
Label call_to_object, use_global_receiver, push_receiver;
|
||||
__ mov(ebx, Operand(ebp, 3 * kPointerSize));
|
||||
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
__ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
|
||||
1 << SharedFunctionInfo::kStrictModeBitWithinByte);
|
||||
__ j(not_equal, &push_receiver);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ test(ebx, Immediate(kSmiTagMask));
|
||||
__ j(zero, &call_to_object);
|
||||
__ cmp(ebx, Factory::null_value());
|
||||
|
@ -4370,7 +4370,6 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kThisPropertyAssignmentsOffset + kPointerSize,
|
||||
kSize> BodyDescriptor;
|
||||
|
||||
private:
|
||||
// Bit positions in start_position_and_type.
|
||||
// The source code start position is in the 30 most significant bits of
|
||||
// the start_position_and_type field.
|
||||
@ -4389,6 +4388,35 @@ class SharedFunctionInfo: public HeapObject {
|
||||
static const int kOptimizationDisabled = 7;
|
||||
static const int kStrictModeFunction = 8;
|
||||
|
||||
private:
|
||||
#if V8_HOST_ARCH_32_BIT
|
||||
// On 32 bit platforms, compiler hints is a smi.
|
||||
static const int kCompilerHintsSmiTagSize = kSmiTagSize;
|
||||
static const int kCompilerHintsSize = kPointerSize;
|
||||
#else
|
||||
// On 64 bit platforms, compiler hints is not a smi, see comment above.
|
||||
static const int kCompilerHintsSmiTagSize = 0;
|
||||
static const int kCompilerHintsSize = kIntSize;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Constants for optimizing codegen for strict mode function tests.
|
||||
// Allows to use byte-widgh instructions.
|
||||
static const int kStrictModeBitWithinByte =
|
||||
(kStrictModeFunction + kCompilerHintsSmiTagSize) % kBitsPerByte;
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
static const int kStrictModeByteOffset = kCompilerHintsOffset +
|
||||
(kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
static const int kStrictModeByteOffset = kCompilerHintsOffset +
|
||||
(kCompilerHintsSize - 1) -
|
||||
((kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
|
||||
#else
|
||||
#error Unknown byte ordering
|
||||
#endif
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
|
||||
};
|
||||
|
||||
|
@ -651,6 +651,13 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
// Change context eagerly in case we need the global receiver.
|
||||
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
|
||||
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
__ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ testb(FieldOperand(rbx, SharedFunctionInfo::kStrictModeByteOffset),
|
||||
Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
|
||||
__ j(not_equal, &shift_arguments);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
|
||||
__ JumpIfSmi(rbx, &convert_to_object);
|
||||
|
||||
@ -807,6 +814,14 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
// Compute the receiver.
|
||||
Label call_to_object, use_global_receiver, push_receiver;
|
||||
__ movq(rbx, Operand(rbp, kReceiverOffset));
|
||||
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
__ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
|
||||
Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
|
||||
__ j(not_equal, &push_receiver);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ JumpIfSmi(rbx, &call_to_object);
|
||||
__ CompareRoot(rbx, Heap::kNullValueRootIndex);
|
||||
__ j(equal, &use_global_receiver);
|
||||
|
@ -239,15 +239,6 @@ chapter15/15.10/15.10.7/15.10.7.5/15.10.7.5-2: FAIL_OK
|
||||
# Incorrect test - need double escape in eval.
|
||||
chapter07/7.8/7.8.4/7.8.4-1-s: FAIL
|
||||
|
||||
# this is not coerced to an object in strict mode (Number)
|
||||
chapter10/10.4/10.4.3/10.4.3-1-1-s: FAIL
|
||||
# this is not coerced to an object in strict mode (string)
|
||||
chapter10/10.4/10.4.3/10.4.3-1-2-s: FAIL
|
||||
# this is not coerced to an object in strict mode (undefined)
|
||||
chapter10/10.4/10.4.3/10.4.3-1-3-s: FAIL
|
||||
# this is not coerced to an object in strict mode (boolean)
|
||||
chapter10/10.4/10.4.3/10.4.3-1-4-s: FAIL
|
||||
|
||||
# arguments[i] remains same after changing actual parameters in strict mode
|
||||
chapter10/10.6/10.6-10-c-ii-1-s: FAIL
|
||||
# arguments[i] doesn't map to actual parameters in strict mode
|
||||
@ -436,53 +427,13 @@ chapter13/13.1/13.1-3-11-s: FAIL
|
||||
# Test fails to return true on success (invalid test case).
|
||||
chapter13/13.1/13.1-3-12-s: FAIL
|
||||
|
||||
# 'use strict' directive - correct usage
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-1-s: FAIL
|
||||
# "use strict" directive - correct usage double quotes
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-2-s: FAIL
|
||||
# 'use strict' directive - may follow other directives
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-8-s: FAIL
|
||||
# 'use strict' directive - may occur multiple times
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-9-s: FAIL
|
||||
# other directives - may follow 'use strict' directive
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-10-s: FAIL
|
||||
# comments may preceed 'use strict' directive
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-11-s: FAIL
|
||||
# comments may follow 'use strict' directive
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-12-s: FAIL
|
||||
# semicolon insertion works for'use strict' directive
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-13-s: FAIL
|
||||
# semicolon insertion may come before 'use strict' directive
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-14-s: FAIL
|
||||
# blank lines may come before 'use strict' directive
|
||||
# depends on "this is not coerced to an object in strict mode (undefined)"
|
||||
chapter14/14.1/14.1-15-s: FAIL
|
||||
|
||||
# Duplicate combined parameter name allowed in Function constructor called
|
||||
# in strict mode if body not strict
|
||||
# Test fails to return true on success (invalid test case).
|
||||
chapter15/15.3/15.3.2/15.3.2.1/15.3.2.1-11-6-s: FAIL
|
||||
|
||||
# Array.prototype.every - thisArg not passed to strict callbackfn
|
||||
chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-5-1-s: FAIL
|
||||
# Array.prototype.some - thisArg not passed to strict callbackfn
|
||||
chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-5-1-s: FAIL
|
||||
# Array.prototype.forEach - thisArg not passed to strict callbackfn
|
||||
chapter15/15.4/15.4.4/15.4.4.18/15.4.4.18-5-1-s: FAIL
|
||||
# Array.prototype.map - thisArg not passed to strict callbackfn
|
||||
chapter15/15.4/15.4.4/15.4.4.19/15.4.4.19-5-1-s: FAIL
|
||||
# Array.prototype.filter - thisArg not passed to strict callbackfn
|
||||
chapter15/15.4/15.4.4/15.4.4.20/15.4.4.20-5-1-s: FAIL
|
||||
# Array.prototype.reduce - null passed as thisValue to strict callbackfn
|
||||
# Invalid test case: http://es5conform.codeplex.com/workitem/29085
|
||||
chapter15/15.4/15.4.4/15.4.4.21/15.4.4.21-9-c-ii-4-s: FAIL
|
||||
|
||||
[ $arch == mips ]
|
||||
|
@ -436,3 +436,45 @@ repeat(10, function() { testAssignToUndefined(false); });
|
||||
assertThrows(function() { delete_element(object, 3.14); }, TypeError);
|
||||
assertEquals(object[3.14], "pi");
|
||||
})();
|
||||
|
||||
// Not transforming this in Function.call and Function.apply.
|
||||
(function testThisTransform() {
|
||||
function non_strict() {
|
||||
return this;
|
||||
}
|
||||
function strict() {
|
||||
"use strict";
|
||||
return this;
|
||||
}
|
||||
|
||||
var global_object = (function() { return this; })();
|
||||
var object = {};
|
||||
|
||||
// Non-strict call.
|
||||
assertTrue(non_strict.call(null) === global_object);
|
||||
assertTrue(non_strict.call(undefined) === global_object);
|
||||
assertEquals(typeof non_strict.call(7), "object");
|
||||
assertEquals(typeof non_strict.call("Hello"), "object");
|
||||
assertTrue(non_strict.call(object) === object);
|
||||
|
||||
// Non-strict apply.
|
||||
assertTrue(non_strict.apply(null) === global_object);
|
||||
assertTrue(non_strict.apply(undefined) === global_object);
|
||||
assertEquals(typeof non_strict.apply(7), "object");
|
||||
assertEquals(typeof non_strict.apply("Hello"), "object");
|
||||
assertTrue(non_strict.apply(object) === object);
|
||||
|
||||
// Strict call.
|
||||
assertTrue(strict.call(null) === null);
|
||||
assertTrue(strict.call(undefined) === undefined);
|
||||
assertEquals(typeof strict.call(7), "number");
|
||||
assertEquals(typeof strict.call("Hello"), "string");
|
||||
assertTrue(strict.call(object) === object);
|
||||
|
||||
// Strict apply.
|
||||
assertTrue(strict.apply(null) === null);
|
||||
assertTrue(strict.apply(undefined) === undefined);
|
||||
assertEquals(typeof strict.apply(7), "number");
|
||||
assertEquals(typeof strict.apply("Hello"), "string");
|
||||
assertTrue(strict.apply(object) === object);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user