Only send null or undefined as receiver for es5 natives, not generally
for builtin functions. Review URL: http://codereview.chromium.org/7012012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7879 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
658e323e87
commit
964dbff40d
@ -1243,15 +1243,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
kSmiTagSize)));
|
||||
__ b(ne, &shift_arguments);
|
||||
|
||||
// Do not transform the receiver for native (shared already in r2).
|
||||
__ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kScriptOffset));
|
||||
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
|
||||
__ cmp(r2, r3);
|
||||
__ b(eq, &shift_arguments);
|
||||
__ ldr(r2, FieldMemOperand(r2, Script::kTypeOffset));
|
||||
__ mov(r2, Operand(r2, ASR, kSmiTagSize));
|
||||
__ cmp(r2, Operand(Script::TYPE_NATIVE));
|
||||
__ b(eq, &shift_arguments);
|
||||
// Do not transform the receiver for native (Compilerhints already in r3).
|
||||
__ tst(r3, Operand(1 << (SharedFunctionInfo::kES5Native +
|
||||
kSmiTagSize)));
|
||||
__ b(ne, &shift_arguments);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
@ -1262,7 +1257,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ tst(r2, Operand(kSmiTagMask));
|
||||
__ b(eq, &convert_to_object);
|
||||
|
||||
// Heap::kUndefinedValueRootIndex is already in r3.
|
||||
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
|
||||
__ cmp(r2, r3);
|
||||
__ b(eq, &use_global_receiver);
|
||||
__ LoadRoot(r3, Heap::kNullValueRootIndex);
|
||||
@ -1431,15 +1426,10 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
kSmiTagSize)));
|
||||
__ b(ne, &push_receiver);
|
||||
|
||||
// Do not transform the receiver for native (shared already in r1).
|
||||
__ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kScriptOffset));
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ cmp(r1, r2);
|
||||
__ b(eq, &push_receiver);
|
||||
__ ldr(r1, FieldMemOperand(r1, Script::kTypeOffset));
|
||||
__ mov(r1, Operand(r1, ASR, kSmiTagSize));
|
||||
__ cmp(r1, Operand(Script::TYPE_NATIVE));
|
||||
__ b(eq, &push_receiver);
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
__ tst(r2, Operand(1 << (SharedFunctionInfo::kES5Native +
|
||||
kSmiTagSize)));
|
||||
__ b(ne, &push_receiver);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ tst(r0, Operand(kSmiTagMask));
|
||||
@ -1447,8 +1437,8 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ LoadRoot(r1, Heap::kNullValueRootIndex);
|
||||
__ cmp(r0, r1);
|
||||
__ b(eq, &use_global_receiver);
|
||||
// Heap::kUndefinedValueRootIndex is already in r2.
|
||||
__ cmp(r0, r2);
|
||||
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
|
||||
__ cmp(r0, r1);
|
||||
__ b(eq, &use_global_receiver);
|
||||
|
||||
// Check if the receiver is already a JavaScript object.
|
||||
|
@ -2377,6 +2377,7 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
|
||||
share->set_num_literals(0);
|
||||
share->set_end_position(0);
|
||||
share->set_function_token_position(0);
|
||||
share->set_es5_native(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -600,13 +600,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ j(not_equal, &shift_arguments);
|
||||
|
||||
// Do not transform the receiver for natives (shared already in ebx).
|
||||
__ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kScriptOffset));
|
||||
__ cmp(ebx, factory->undefined_value());
|
||||
__ j(equal, &shift_arguments);
|
||||
__ mov(ebx, FieldOperand(ebx, Script::kTypeOffset));
|
||||
__ SmiUntag(ebx);
|
||||
__ cmp(ebx, Script::TYPE_NATIVE);
|
||||
__ j(equal, &shift_arguments);
|
||||
__ test_b(FieldOperand(ebx, SharedFunctionInfo::kES5NativeByteOffset),
|
||||
1 << SharedFunctionInfo::kES5NativeBitWithinByte);
|
||||
__ j(not_equal, &shift_arguments);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
|
||||
@ -767,13 +763,9 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
Factory* factory = masm->isolate()->factory();
|
||||
|
||||
// Do not transform the receiver for natives (shared already in ecx).
|
||||
__ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kScriptOffset));
|
||||
__ cmp(ecx, factory->undefined_value());
|
||||
__ j(equal, &push_receiver);
|
||||
__ mov(ecx, FieldOperand(ecx, Script::kTypeOffset));
|
||||
__ SmiUntag(ecx);
|
||||
__ cmp(ecx, Script::TYPE_NATIVE);
|
||||
__ j(equal, &push_receiver);
|
||||
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kES5NativeByteOffset),
|
||||
1 << SharedFunctionInfo::kES5NativeBitWithinByte);
|
||||
__ j(not_equal, &push_receiver);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ test(ebx, Immediate(kSmiTagMask));
|
||||
|
@ -3218,6 +3218,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) {
|
||||
}
|
||||
|
||||
|
||||
bool SharedFunctionInfo::es5_native() {
|
||||
return BooleanBit::get(compiler_hints(), kES5Native);
|
||||
}
|
||||
|
||||
|
||||
void SharedFunctionInfo::set_es5_native(bool value) {
|
||||
set_compiler_hints(BooleanBit::set(compiler_hints(),
|
||||
kES5Native,
|
||||
value));
|
||||
}
|
||||
|
||||
|
||||
ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
|
||||
ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
|
||||
|
||||
|
@ -4349,6 +4349,13 @@ class SharedFunctionInfo: public HeapObject {
|
||||
inline bool strict_mode();
|
||||
inline void set_strict_mode(bool value);
|
||||
|
||||
// Indicates whether the function is a native ES5 function.
|
||||
// These needs special threatment in .call and .apply since
|
||||
// null passed as the receiver should not be translated to the
|
||||
// global object.
|
||||
inline bool es5_native();
|
||||
inline void set_es5_native(bool value);
|
||||
|
||||
// Indicates whether or not the code in the shared function support
|
||||
// deoptimization.
|
||||
inline bool has_deoptimization_support();
|
||||
@ -4529,6 +4536,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
static const int kCodeAgeMask = 0x7;
|
||||
static const int kOptimizationDisabled = 6;
|
||||
static const int kStrictModeFunction = 7;
|
||||
static const int kES5Native = 8;
|
||||
|
||||
private:
|
||||
#if V8_HOST_ARCH_32_BIT
|
||||
@ -4542,18 +4550,27 @@ class SharedFunctionInfo: public HeapObject {
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Constants for optimizing codegen for strict mode function tests.
|
||||
// Constants for optimizing codegen for strict mode function and
|
||||
// es5 native tests.
|
||||
// Allows to use byte-widgh instructions.
|
||||
static const int kStrictModeBitWithinByte =
|
||||
(kStrictModeFunction + kCompilerHintsSmiTagSize) % kBitsPerByte;
|
||||
|
||||
static const int kES5NativeBitWithinByte =
|
||||
(kES5Native + kCompilerHintsSmiTagSize) % kBitsPerByte;
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
static const int kStrictModeByteOffset = kCompilerHintsOffset +
|
||||
(kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
|
||||
(kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte;
|
||||
static const int kES5NativeByteOffset = kCompilerHintsOffset +
|
||||
(kES5Native + kCompilerHintsSmiTagSize) / kBitsPerByte;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
static const int kStrictModeByteOffset = kCompilerHintsOffset +
|
||||
(kCompilerHintsSize - 1) -
|
||||
((kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
|
||||
(kCompilerHintsSize - 1) -
|
||||
((kStrictModeFunction + kCompilerHintsSmiTagSize) / kBitsPerByte);
|
||||
static const int kES5NativeByteOffset = kCompilerHintsOffset +
|
||||
(kCompilerHintsSize - 1) -
|
||||
((kES5Native + kCompilerHintsSmiTagSize) / kBitsPerByte);
|
||||
#else
|
||||
#error Unknown byte ordering
|
||||
#endif
|
||||
|
@ -4107,6 +4107,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
|
||||
}
|
||||
|
||||
|
||||
// Set the ES5 native flag on the function.
|
||||
// This is used to decide if we should transform null and undefined
|
||||
// into the global object when doing call and apply.
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
|
||||
NoHandleAllocation ha;
|
||||
RUNTIME_ASSERT(args.length() == 1);
|
||||
|
||||
Handle<Object> object = args.at<Object>(0);
|
||||
|
||||
if (object->IsJSFunction()) {
|
||||
JSFunction* func = JSFunction::cast(*object);
|
||||
func->shared()->set_es5_native(true);
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Set a local property, even if it is READ_ONLY. If the property does not
|
||||
// exist, it will be added with attributes NONE.
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
|
||||
|
@ -92,6 +92,7 @@ namespace internal {
|
||||
F(CompileForOnStackReplacement, 1, 1) \
|
||||
F(SetNewFunctionAttributes, 1, 1) \
|
||||
F(AllocateInNewSpace, 1, 1) \
|
||||
F(SetES5Flag, 1, 1) \
|
||||
\
|
||||
/* Array join support */ \
|
||||
F(PushIfAbsent, 2, 1) \
|
||||
|
@ -56,6 +56,7 @@ function InstallFunctions(object, attributes, functions) {
|
||||
%FunctionSetName(f, key);
|
||||
%FunctionRemovePrototype(f);
|
||||
%SetProperty(object, key, f, attributes);
|
||||
%SetES5Flag(f);
|
||||
}
|
||||
%ToFastProperties(object);
|
||||
}
|
||||
|
@ -660,12 +660,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
|
||||
// Do not transform the receiver for natives.
|
||||
// SharedFunctionInfo is already loaded into rbx.
|
||||
__ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kScriptOffset));
|
||||
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, &shift_arguments);
|
||||
__ SmiCompare(FieldOperand(rbx, Script::kTypeOffset),
|
||||
Smi::FromInt(Script::TYPE_NATIVE));
|
||||
__ j(equal, &shift_arguments);
|
||||
__ testb(FieldOperand(rbx, SharedFunctionInfo::kES5NativeByteOffset),
|
||||
Immediate(1 << SharedFunctionInfo::kES5NativeBitWithinByte));
|
||||
__ j(not_zero, &shift_arguments);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
|
||||
@ -832,13 +829,9 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ j(not_equal, &push_receiver);
|
||||
|
||||
// Do not transform the receiver for natives.
|
||||
// SharedFunctionInfo is already loaded into rdx.
|
||||
__ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kScriptOffset));
|
||||
__ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, &push_receiver);
|
||||
__ SmiCompare(FieldOperand(rdx, Script::kTypeOffset),
|
||||
Smi::FromInt(Script::TYPE_NATIVE));
|
||||
__ j(equal, &push_receiver);
|
||||
__ testb(FieldOperand(rdx, SharedFunctionInfo::kES5NativeByteOffset),
|
||||
Immediate(1 << SharedFunctionInfo::kES5NativeBitWithinByte));
|
||||
__ j(not_zero, &push_receiver);
|
||||
|
||||
// Compute the receiver in non-strict mode.
|
||||
__ JumpIfSmi(rbx, &call_to_object);
|
||||
|
@ -14452,5 +14452,4 @@ THREADED_TEST(CallAPIFunctionOnNonObject) {
|
||||
context->Global()->Set(v8_str("f"), function);
|
||||
TryCatch try_catch;
|
||||
CompileRun("f.call(2)");
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
|
@ -27,5 +27,5 @@
|
||||
|
||||
// Flags: --expose-gc
|
||||
|
||||
assertThrows('gc.call(1)');
|
||||
assertThrows('gc.call("asdf")');
|
||||
assertDoesNotThrow('gc.call(1)');
|
||||
assertDoesNotThrow('gc.call("asdf")');
|
||||
|
Loading…
Reference in New Issue
Block a user