Revert "Load the global proxy from the context of the target function."
This reverts commit https://code.google.com/p/v8/source/detail?r=18458, since it exhibits a bug that breaks some tests. TBR=verwaest@chromium.org BUG= Review URL: https://codereview.chromium.org/93863006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18461 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4934263a77
commit
2879f2104c
@ -34,7 +34,6 @@
|
||||
#include "deoptimizer.h"
|
||||
#include "full-codegen.h"
|
||||
#include "runtime.h"
|
||||
#include "stub-cache.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -1092,8 +1091,12 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
// Use the global receiver object from the called function as the
|
||||
// receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
__ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
|
||||
const int kGlobalIndex =
|
||||
Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
|
||||
__ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kNativeContextOffset));
|
||||
__ ldr(r2, FieldMemOperand(r2, kGlobalIndex));
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ bind(&patch_receiver);
|
||||
__ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||
@ -1284,7 +1287,11 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
|
||||
// Use the current global receiver object as the receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
__ ldr(r0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
const int kGlobalOffset =
|
||||
Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
|
||||
__ ldr(r0, FieldMemOperand(cp, kGlobalOffset));
|
||||
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
|
||||
__ ldr(r0, FieldMemOperand(r0, kGlobalOffset));
|
||||
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
// Push the receiver.
|
||||
|
@ -3182,48 +3182,32 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
// r2 : cache cell for call target
|
||||
Label slow, non_function;
|
||||
|
||||
// Check that the function is really a JavaScript function.
|
||||
// r1: pushed function (to be verified)
|
||||
__ JumpIfSmi(r1, &non_function);
|
||||
|
||||
// The receiver might implicitly be the global object. This is
|
||||
// indicated by passing the hole as the receiver to the call
|
||||
// function stub.
|
||||
if (ReceiverMightBeImplicit() || ReceiverIsImplicit()) {
|
||||
Label try_call, call, patch_current_context;
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
// Get the receiver from the stack.
|
||||
// function, receiver [, arguments]
|
||||
__ ldr(r4, MemOperand(sp, argc_ * kPointerSize));
|
||||
// Call as function is indicated with the hole.
|
||||
__ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
|
||||
__ b(ne, &try_call);
|
||||
}
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
Label call;
|
||||
// Get the receiver from the stack.
|
||||
// function, receiver [, arguments]
|
||||
__ ldr(r4, MemOperand(sp, argc_ * kPointerSize));
|
||||
// Call as function is indicated with the hole.
|
||||
__ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
|
||||
__ b(ne, &call);
|
||||
// Patch the receiver on the stack with the global receiver object.
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &patch_current_context);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, r3, r1);
|
||||
__ ldr(r3,
|
||||
MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalReceiverOffset));
|
||||
__ str(r3, MemOperand(sp, argc_ * kPointerSize));
|
||||
__ jmp(&call);
|
||||
|
||||
__ bind(&patch_current_context);
|
||||
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
||||
__ str(ip, MemOperand(sp, argc_ * kPointerSize));
|
||||
__ jmp(&slow);
|
||||
|
||||
__ bind(&try_call);
|
||||
// Get the map of the function object.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &slow);
|
||||
|
||||
__ bind(&call);
|
||||
} else {
|
||||
// Get the map of the function object.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &slow);
|
||||
}
|
||||
|
||||
// Check that the function is really a JavaScript function.
|
||||
// r1: pushed function (to be verified)
|
||||
__ JumpIfSmi(r1, &non_function);
|
||||
// Get the map of the function object.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &slow);
|
||||
|
||||
if (RecordCallTarget()) {
|
||||
GenerateRecordCallTarget(masm);
|
||||
}
|
||||
@ -3267,7 +3251,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
__ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32));
|
||||
__ mov(r2, Operand::Zero());
|
||||
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
|
||||
__ SetCallKind(r5, CALL_AS_FUNCTION);
|
||||
__ SetCallKind(r5, CALL_AS_METHOD);
|
||||
{
|
||||
Handle<Code> adaptor =
|
||||
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
|
||||
|
@ -2815,12 +2815,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(callee);
|
||||
}
|
||||
// Push the hole as receiver.
|
||||
// It will be correctly replaced in the call stub.
|
||||
__ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
|
||||
// Load global receiver object.
|
||||
__ ldr(r1, GlobalObjectOperand());
|
||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
|
||||
__ push(r1);
|
||||
// Emit function call.
|
||||
EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -491,7 +491,7 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
|
||||
|
||||
// Patch the receiver on the stack.
|
||||
__ bind(&global);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, r2, r1);
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
|
||||
__ str(r2, MemOperand(sp, argc * kPointerSize));
|
||||
__ bind(&invoke);
|
||||
}
|
||||
|
@ -3491,8 +3491,11 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
__ b(&result_in_receiver);
|
||||
|
||||
__ bind(&global_object);
|
||||
CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
|
||||
|
||||
__ ldr(result, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
__ ldr(result, ContextOperand(result, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(result,
|
||||
FieldMemOperand(result, JSGlobalObject::kGlobalReceiverOffset));
|
||||
if (result.is(receiver)) {
|
||||
__ bind(&result_in_receiver);
|
||||
} else {
|
||||
@ -3990,10 +3993,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
||||
ASSERT(ToRegister(instr->result()).is(r0));
|
||||
|
||||
int arity = instr->arity();
|
||||
CallFunctionFlags flags =
|
||||
instr->hydrogen()->IsContextualCall() ?
|
||||
RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
|
||||
CallFunctionStub stub(arity, flags);
|
||||
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
|
||||
if (instr->hydrogen()->IsTailCall()) {
|
||||
if (NeedsEagerFrame()) __ mov(sp, fp);
|
||||
__ Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
|
||||
|
@ -2341,23 +2341,11 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
|
||||
if (object->IsGlobalObject()) {
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = argc * kPointerSize;
|
||||
__ Move(r3, handle(function->context()->global_proxy()));
|
||||
__ str(r3, MemOperand(sp, receiver_offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Register function) {
|
||||
if (object->IsGlobalObject()) {
|
||||
FetchGlobalProxy(masm(), r3, function);
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = argc * kPointerSize;
|
||||
__ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
|
||||
__ str(r3, MemOperand(sp, receiver_offset));
|
||||
}
|
||||
}
|
||||
@ -2456,7 +2444,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
ASSERT(function.is(r1));
|
||||
// Check that the function really is a function.
|
||||
GenerateFunctionCheck(function, r3, miss);
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchGlobalProxy(object);
|
||||
|
||||
// Invoke the function.
|
||||
__ InvokeFunction(r1, arguments(), JUMP_FUNCTION,
|
||||
@ -2574,15 +2562,6 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
|
||||
void CallStubCompiler::FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function) {
|
||||
__ ldr(target, FieldMemOperand(function, JSFunction::kContextOffset));
|
||||
__ ldr(target, ContextOperand(target, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(target, FieldMemOperand(target, GlobalObject::kGlobalReceiverOffset));
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm,
|
||||
Handle<JSFunction> setter) {
|
||||
|
@ -1669,8 +1669,6 @@ bool Genesis::InstallNatives() {
|
||||
builtins->set_native_context(*native_context());
|
||||
builtins->set_global_context(*native_context());
|
||||
builtins->set_global_receiver(*builtins);
|
||||
builtins->set_global_receiver(native_context()->global_proxy());
|
||||
|
||||
|
||||
// Set up the 'global' properties of the builtins object. The
|
||||
// 'global' property that refers to the global object is the only
|
||||
@ -1684,11 +1682,6 @@ bool Genesis::InstallNatives() {
|
||||
CHECK_NOT_EMPTY_HANDLE(isolate(),
|
||||
JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
builtins, global_string, global_obj, attributes));
|
||||
Handle<String> builtins_string =
|
||||
factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("builtins"));
|
||||
CHECK_NOT_EMPTY_HANDLE(isolate(),
|
||||
JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
builtins, builtins_string, builtins, attributes));
|
||||
|
||||
// Set up the reference from the global object to the builtins object.
|
||||
JSGlobalObject::cast(native_context()->global_object())->
|
||||
@ -2588,8 +2581,6 @@ Genesis::Genesis(Isolate* isolate,
|
||||
|
||||
HookUpGlobalProxy(inner_global, global_proxy);
|
||||
HookUpInnerGlobal(inner_global);
|
||||
native_context()->builtins()->set_global_receiver(
|
||||
native_context()->global_proxy());
|
||||
|
||||
if (!ConfigureGlobalObjects(global_template)) return;
|
||||
} else {
|
||||
|
@ -1550,8 +1550,8 @@ class CallFunctionStub: public PlatformCodeStub {
|
||||
virtual void PrintName(StringStream* stream);
|
||||
|
||||
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
|
||||
class FlagBits: public BitField<CallFunctionFlags, 0, 3> {};
|
||||
class ArgcBits: public BitField<unsigned, 3, 32 - 3> {};
|
||||
class FlagBits: public BitField<CallFunctionFlags, 0, 2> {};
|
||||
class ArgcBits: public BitField<unsigned, 2, 32 - 2> {};
|
||||
|
||||
Major MajorKey() { return CallFunction; }
|
||||
int MinorKey() {
|
||||
@ -1563,10 +1563,6 @@ class CallFunctionStub: public PlatformCodeStub {
|
||||
return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
|
||||
}
|
||||
|
||||
bool ReceiverIsImplicit() {
|
||||
return (flags_ & RECEIVER_IS_IMPLICIT) != 0;
|
||||
}
|
||||
|
||||
bool RecordCallTarget() {
|
||||
return (flags_ & RECORD_CALL_TARGET) != 0;
|
||||
}
|
||||
|
@ -2414,8 +2414,7 @@ class HCallNamed V8_FINAL : public HUnaryCall {
|
||||
|
||||
enum CallMode {
|
||||
NORMAL_CALL,
|
||||
TAIL_CALL,
|
||||
NORMAL_CONTEXTUAL_CALL
|
||||
TAIL_CALL
|
||||
};
|
||||
|
||||
|
||||
@ -2426,7 +2425,7 @@ class HCallFunction V8_FINAL : public HBinaryCall {
|
||||
HCallFunction, HValue*, int, CallMode);
|
||||
|
||||
bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
|
||||
bool IsContextualCall() const { return call_mode_ == NORMAL_CONTEXTUAL_CALL; }
|
||||
|
||||
HValue* context() { return first(); }
|
||||
HValue* function() { return second(); }
|
||||
|
||||
|
@ -7618,27 +7618,6 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::InstallGlobalReceiverInExpressionStack(
|
||||
int receiver_index,
|
||||
Handle<JSFunction> function) {
|
||||
// TODO(dcarney): Fix deserializer to be able to hookup the global receiver
|
||||
// and object during deserialization and embed the global receiver here
|
||||
// directly.
|
||||
// Install global receiver on stack.
|
||||
HValue* function_constant = Add<HConstant>(function);
|
||||
HValue* context = Add<HLoadNamedField>(
|
||||
function_constant,
|
||||
HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset));
|
||||
HValue* global_object = Add<HLoadNamedField>(
|
||||
context,
|
||||
HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
|
||||
HValue* global_receiver = Add<HLoadNamedField>(
|
||||
global_object,
|
||||
HObjectAccess::ForJSObjectOffset(GlobalObject::kGlobalReceiverOffset));
|
||||
environment()->SetExpressionStackAt(receiver_index, global_receiver);
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
@ -7759,11 +7738,13 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
HValue* function = Pop();
|
||||
Add<HCheckValue>(function, expr->target());
|
||||
|
||||
// Install global receiver on stack.
|
||||
// Replace the global object with the global receiver.
|
||||
HGlobalReceiver* global_receiver = Add<HGlobalReceiver>(global_object);
|
||||
// Index of the receiver from the top of the expression stack.
|
||||
const int receiver_index = argument_count - 1;
|
||||
ASSERT(environment()->ExpressionStackAt(receiver_index)->
|
||||
IsGlobalObject());
|
||||
InstallGlobalReceiverInExpressionStack(receiver_index, expr->target());
|
||||
environment()->SetExpressionStackAt(receiver_index, global_receiver);
|
||||
|
||||
if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop.
|
||||
if (FLAG_trace_inlining) {
|
||||
@ -7780,12 +7761,9 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
}
|
||||
|
||||
if (CallStubCompiler::HasCustomCallGenerator(expr->target())) {
|
||||
// We're about to install a contextual IC, which expects the global
|
||||
// object as receiver rather than the global proxy.
|
||||
environment()->SetExpressionStackAt(receiver_index, global_object);
|
||||
// When the target has a custom call IC generator, use the IC,
|
||||
// because it is likely to generate better code.
|
||||
call = PreProcessCall(New<HCallGlobal>(var->name(), argument_count));
|
||||
call = PreProcessCall(New<HCallNamed>(var->name(), argument_count));
|
||||
} else {
|
||||
call = PreProcessCall(New<HCallKnownGlobal>(
|
||||
expr->target(), argument_count));
|
||||
@ -7810,12 +7788,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
||||
Add<HCheckValue>(function, expr->target());
|
||||
|
||||
// Install global receiver on stack.
|
||||
const int receiver_index = argument_count - 1;
|
||||
ASSERT(environment()->ExpressionStackAt(receiver_index)->
|
||||
IsGlobalReceiver());
|
||||
InstallGlobalReceiverInExpressionStack(receiver_index, expr->target());
|
||||
|
||||
if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function.
|
||||
if (FLAG_trace_inlining) {
|
||||
PrintF("Inlining builtin ");
|
||||
@ -7836,11 +7808,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
} else {
|
||||
CHECK_ALIVE(VisitForValue(expr->expression()));
|
||||
HValue* function = Top();
|
||||
HValue* receiver = graph()->GetConstantHole();
|
||||
HGlobalObject* global_object = Add<HGlobalObject>();
|
||||
HGlobalReceiver* receiver = Add<HGlobalReceiver>(global_object);
|
||||
Push(Add<HPushArgument>(receiver));
|
||||
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
||||
call = New<HCallFunction>(
|
||||
function, argument_count, NORMAL_CONTEXTUAL_CALL);
|
||||
|
||||
call = New<HCallFunction>(function, argument_count);
|
||||
Drop(argument_count + 1);
|
||||
}
|
||||
}
|
||||
|
@ -2502,9 +2502,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
HValue* receiver,
|
||||
Handle<Map> receiver_map);
|
||||
|
||||
void InstallGlobalReceiverInExpressionStack(int index,
|
||||
Handle<JSFunction> function);
|
||||
|
||||
// The translation state of the currently-being-translated function.
|
||||
FunctionState* function_state_;
|
||||
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "codegen.h"
|
||||
#include "deoptimizer.h"
|
||||
#include "full-codegen.h"
|
||||
#include "stub-cache.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -784,7 +783,12 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
// Use the global receiver object from the called function as the
|
||||
// receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, ebx, edi);
|
||||
const int kGlobalIndex =
|
||||
Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
|
||||
__ mov(ebx, FieldOperand(esi, kGlobalIndex));
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
|
||||
__ mov(ebx, FieldOperand(ebx, kGlobalIndex));
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ bind(&patch_receiver);
|
||||
__ mov(Operand(esp, eax, times_4, 0), ebx);
|
||||
@ -957,7 +961,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
|
||||
// Use the current global receiver object as the receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, ebx, edi);
|
||||
const int kGlobalOffset =
|
||||
Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
|
||||
__ mov(ebx, FieldOperand(esi, kGlobalOffset));
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
|
||||
__ mov(ebx, FieldOperand(ebx, kGlobalOffset));
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
// Push the receiver.
|
||||
__ bind(&push_receiver);
|
||||
|
@ -2517,47 +2517,30 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
Isolate* isolate = masm->isolate();
|
||||
Label slow, non_function;
|
||||
|
||||
// Check that the function really is a JavaScript function.
|
||||
__ JumpIfSmi(edi, &non_function);
|
||||
|
||||
// The receiver might implicitly be the global object. This is
|
||||
// indicated by passing the hole as the receiver to the call
|
||||
// function stub.
|
||||
if (ReceiverMightBeImplicit() || ReceiverIsImplicit()) {
|
||||
Label try_call, call, patch_current_context;
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
// Get the receiver from the stack.
|
||||
// +1 ~ return address
|
||||
__ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
|
||||
// Call as function is indicated with the hole.
|
||||
__ cmp(eax, isolate->factory()->the_hole_value());
|
||||
__ j(not_equal, &try_call, Label::kNear);
|
||||
}
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
Label receiver_ok;
|
||||
// Get the receiver from the stack.
|
||||
// +1 ~ return address
|
||||
__ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
|
||||
// Call as function is indicated with the hole.
|
||||
__ cmp(eax, isolate->factory()->the_hole_value());
|
||||
__ j(not_equal, &receiver_ok, Label::kNear);
|
||||
// Patch the receiver on the stack with the global receiver object.
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &patch_current_context);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, ecx, edi);
|
||||
__ mov(ecx, GlobalObjectOperand());
|
||||
__ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), ecx);
|
||||
__ jmp(&call, Label::kNear);
|
||||
|
||||
__ bind(&patch_current_context);
|
||||
__ mov(edx, isolate->factory()->undefined_value());
|
||||
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx);
|
||||
__ jmp(&slow);
|
||||
|
||||
__ bind(&try_call);
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
__ bind(&call);
|
||||
} else {
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &slow);
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
// Check that the function really is a JavaScript function.
|
||||
__ JumpIfSmi(edi, &non_function);
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
if (RecordCallTarget()) {
|
||||
GenerateRecordCallTarget(masm);
|
||||
}
|
||||
|
@ -2769,11 +2769,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(callee);
|
||||
}
|
||||
// Push the hole as receiver.
|
||||
// It will be correctly replaced in the call stub.
|
||||
__ push(Immediate(isolate()->factory()->the_hole_value()));
|
||||
// Load global receiver object.
|
||||
__ mov(ebx, GlobalObjectOperand());
|
||||
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||
// Emit function call.
|
||||
EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -1112,9 +1112,8 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
|
||||
|
||||
// Patch the receiver on the stack.
|
||||
__ bind(&global);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, edx, edi);
|
||||
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
|
||||
|
||||
__ bind(&invoke);
|
||||
}
|
||||
|
||||
|
@ -3675,7 +3675,10 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
// TODO(kmillikin): We have a hydrogen value for the global object. See
|
||||
// if it's better to use it than to explicitly fetch it from the context
|
||||
// here.
|
||||
CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
|
||||
__ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||
__ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ mov(receiver,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
@ -4242,10 +4245,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
||||
ASSERT(ToRegister(instr->result()).is(eax));
|
||||
|
||||
int arity = instr->arity();
|
||||
CallFunctionFlags flags =
|
||||
instr->hydrogen()->IsContextualCall() ?
|
||||
RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
|
||||
CallFunctionStub stub(arity, flags);
|
||||
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
|
||||
if (instr->hydrogen()->IsTailCall()) {
|
||||
if (NeedsEagerFrame()) __ leave();
|
||||
__ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
|
||||
|
@ -1166,7 +1166,7 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
|
||||
|
||||
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
|
||||
LOperand* receiver = UseRegister(instr->receiver());
|
||||
LOperand* function = UseRegister(instr->function());
|
||||
LOperand* function = UseRegisterAtStart(instr->function());
|
||||
LOperand* temp = TempRegister();
|
||||
LWrapReceiver* result =
|
||||
new(zone()) LWrapReceiver(receiver, function, temp);
|
||||
|
@ -2468,23 +2468,11 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
|
||||
if (object->IsGlobalObject()) {
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = (argc + 1) * kPointerSize;
|
||||
__ LoadHeapObject(edx, handle(function->context()->global_proxy()));
|
||||
__ mov(Operand(esp, receiver_offset), edx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Register function) {
|
||||
if (object->IsGlobalObject()) {
|
||||
FetchGlobalProxy(masm(), edx, function);
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = (argc + 1) * kPointerSize;
|
||||
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ mov(Operand(esp, receiver_offset), edx);
|
||||
}
|
||||
}
|
||||
@ -2578,7 +2566,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
GenerateFunctionCheck(function, ebx, miss);
|
||||
|
||||
if (!function.is(edi)) __ mov(edi, function);
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchGlobalProxy(object);
|
||||
|
||||
// Invoke the function.
|
||||
__ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
|
||||
@ -2693,15 +2681,6 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
|
||||
void CallStubCompiler::FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function) {
|
||||
__ mov(target, FieldOperand(function, JSFunction::kContextOffset));
|
||||
__ mov(target, ContextOperand(target, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ mov(target, FieldOperand(target, GlobalObject::kGlobalReceiverOffset));
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm,
|
||||
Handle<JSFunction> setter) {
|
||||
|
@ -9252,7 +9252,7 @@ static ObjectPair LoadContextSlotHelper(Arguments args,
|
||||
// GetProperty below can cause GC.
|
||||
Handle<Object> receiver_handle(
|
||||
object->IsGlobalObject()
|
||||
? Object::cast(isolate->heap()->the_hole_value())
|
||||
? GlobalObject::cast(*object)->global_receiver()
|
||||
: object->IsJSProxy() ? static_cast<Object*>(*object)
|
||||
: ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
|
||||
isolate);
|
||||
|
@ -48,6 +48,7 @@ var $Number = global.Number;
|
||||
var $Function = global.Function;
|
||||
var $Boolean = global.Boolean;
|
||||
var $NaN = %GetRootNaN();
|
||||
var builtins = this;
|
||||
|
||||
// ECMA-262 Section 11.9.3.
|
||||
function EQUALS(y) {
|
||||
|
@ -1155,7 +1155,7 @@ void CallStubCompiler::GenerateJumpFunctionIgnoreReceiver(
|
||||
|
||||
void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchGlobalProxy(object);
|
||||
GenerateJumpFunctionIgnoreReceiver(function);
|
||||
}
|
||||
|
||||
@ -1163,7 +1163,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
Register actual_closure,
|
||||
Handle<JSFunction> function) {
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchGlobalProxy(object);
|
||||
ParameterCount expected(function);
|
||||
__ InvokeFunction(actual_closure, expected, arguments(),
|
||||
JUMP_FUNCTION, NullCallWrapper(), call_kind());
|
||||
|
@ -912,11 +912,7 @@ class CallStubCompiler: public StubCompiler {
|
||||
|
||||
// Patch the global proxy over the global object if the global object is the
|
||||
// receiver.
|
||||
static void FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function);
|
||||
void PatchGlobalProxy(Handle<Object> object, Register function);
|
||||
void PatchGlobalProxy(Handle<Object> object, Handle<JSFunction> function);
|
||||
void PatchGlobalProxy(Handle<Object> object);
|
||||
|
||||
// Returns the register containing the holder of |name|.
|
||||
Register HandlerFrontendHeader(Handle<Object> object,
|
||||
|
@ -293,10 +293,8 @@ enum CallFunctionFlags {
|
||||
// Receiver might implicitly be the global objects. If it is, the
|
||||
// hole is passed to the call function stub.
|
||||
RECEIVER_MIGHT_BE_IMPLICIT = 1 << 0,
|
||||
// Receiver is implicit and the hole has been passed to the stub.
|
||||
RECEIVER_IS_IMPLICIT = 1 << 1,
|
||||
// The call target is cached in the instruction stream.
|
||||
RECORD_CALL_TARGET = 1 << 2
|
||||
RECORD_CALL_TARGET = 1 << 1
|
||||
};
|
||||
|
||||
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "codegen.h"
|
||||
#include "deoptimizer.h"
|
||||
#include "full-codegen.h"
|
||||
#include "stub-cache.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -847,7 +846,12 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
// Use the global receiver object from the called function as the
|
||||
// receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rbx, rdi);
|
||||
const int kGlobalIndex =
|
||||
Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
|
||||
__ movq(rbx, FieldOperand(rsi, kGlobalIndex));
|
||||
__ movq(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset));
|
||||
__ movq(rbx, FieldOperand(rbx, kGlobalIndex));
|
||||
__ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ bind(&patch_receiver);
|
||||
__ movq(args.GetArgumentOperand(1), rbx);
|
||||
@ -1027,7 +1031,13 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
|
||||
// Use the current global receiver object as the receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rbx, rdi);
|
||||
const int kGlobalOffset =
|
||||
Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
|
||||
__ movq(rbx, FieldOperand(rsi, kGlobalOffset));
|
||||
__ movq(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset));
|
||||
__ movq(rbx, FieldOperand(rbx, kGlobalOffset));
|
||||
__ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
// Push the receiver.
|
||||
__ bind(&push_receiver);
|
||||
__ push(rbx);
|
||||
|
@ -2350,46 +2350,29 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
Label slow, non_function;
|
||||
StackArgumentsAccessor args(rsp, argc_);
|
||||
|
||||
// Check that the function really is a JavaScript function.
|
||||
__ JumpIfSmi(rdi, &non_function);
|
||||
|
||||
// The receiver might implicitly be the global object. This is
|
||||
// indicated by passing the hole as the receiver to the call
|
||||
// function stub.
|
||||
if (ReceiverMightBeImplicit() || ReceiverIsImplicit()) {
|
||||
Label try_call, call, patch_current_context;
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
// Get the receiver from the stack.
|
||||
__ movq(rax, args.GetReceiverOperand());
|
||||
// Call as function is indicated with the hole.
|
||||
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
|
||||
__ j(not_equal, &try_call, Label::kNear);
|
||||
}
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
Label call;
|
||||
// Get the receiver from the stack.
|
||||
__ movq(rax, args.GetReceiverOperand());
|
||||
// Call as function is indicated with the hole.
|
||||
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
|
||||
__ j(not_equal, &call, Label::kNear);
|
||||
// Patch the receiver on the stack with the global receiver object.
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &patch_current_context);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rcx, rdi);
|
||||
__ movq(rcx, GlobalObjectOperand());
|
||||
__ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ movq(args.GetReceiverOperand(), rcx);
|
||||
__ jmp(&call, Label::kNear);
|
||||
|
||||
__ bind(&patch_current_context);
|
||||
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
|
||||
__ movq(args.GetReceiverOperand(), kScratchRegister);
|
||||
__ jmp(&slow);
|
||||
|
||||
__ bind(&try_call);
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
__ bind(&call);
|
||||
} else {
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &slow);
|
||||
}
|
||||
|
||||
// Check that the function really is a JavaScript function.
|
||||
__ JumpIfSmi(rdi, &non_function);
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
if (RecordCallTarget()) {
|
||||
GenerateRecordCallTarget(masm);
|
||||
}
|
||||
@ -2431,7 +2414,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
__ PushReturnAddressFrom(rcx);
|
||||
__ Set(rax, argc_ + 1);
|
||||
__ Set(rbx, 0);
|
||||
__ SetCallKind(rcx, CALL_AS_FUNCTION);
|
||||
__ SetCallKind(rcx, CALL_AS_METHOD);
|
||||
__ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
|
||||
{
|
||||
Handle<Code> adaptor =
|
||||
|
@ -2746,11 +2746,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(callee);
|
||||
}
|
||||
// Push the hole as receiver.
|
||||
// It will be correctly replaced in the call stub.
|
||||
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
||||
// Load global receiver object.
|
||||
__ movq(rbx, GlobalObjectOperand());
|
||||
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
// Emit function call.
|
||||
EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -998,7 +998,7 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
|
||||
|
||||
// Patch the receiver on the stack.
|
||||
__ bind(&global);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rdx, rdi);
|
||||
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ movq(args.GetReceiverOperand(), rdx);
|
||||
__ bind(&invoke);
|
||||
}
|
||||
|
@ -3250,7 +3250,10 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
// TODO(kmillikin): We have a hydrogen value for the global object. See
|
||||
// if it's better to use it than to explicitly fetch it from the context
|
||||
// here.
|
||||
CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
|
||||
__ movq(receiver, Operand(rbp, StandardFrameConstants::kContextOffset));
|
||||
__ movq(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ movq(receiver,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
@ -3815,10 +3818,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
||||
ASSERT(ToRegister(instr->result()).is(rax));
|
||||
|
||||
int arity = instr->arity();
|
||||
CallFunctionFlags flags =
|
||||
instr->hydrogen()->IsContextualCall() ?
|
||||
RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
|
||||
CallFunctionStub stub(arity, flags);
|
||||
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
|
||||
if (instr->hydrogen()->IsTailCall()) {
|
||||
if (NeedsEagerFrame()) __ leave();
|
||||
__ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
|
||||
|
@ -2378,21 +2378,10 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
|
||||
if (object->IsGlobalObject()) {
|
||||
StackArgumentsAccessor args(rsp, arguments());
|
||||
__ MoveHeapObject(rdx, handle(function->context()->global_proxy()));
|
||||
__ movq(args.GetReceiverOperand(), rdx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Register function) {
|
||||
if (object->IsGlobalObject()) {
|
||||
FetchGlobalProxy(masm(), rdx, function);
|
||||
StackArgumentsAccessor args(rsp, arguments().immediate());
|
||||
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ movq(args.GetReceiverOperand(), rdx);
|
||||
}
|
||||
}
|
||||
@ -2486,7 +2475,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
GenerateFunctionCheck(function, rbx, miss);
|
||||
|
||||
if (!function.is(rdi)) __ movq(rdi, function);
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchGlobalProxy(object);
|
||||
|
||||
// Invoke the function.
|
||||
__ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
|
||||
@ -2599,15 +2588,6 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
|
||||
void CallStubCompiler::FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function) {
|
||||
__ movq(target, FieldOperand(function, JSFunction::kContextOffset));
|
||||
__ movq(target, ContextOperand(target, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ movq(target, FieldOperand(target, GlobalObject::kGlobalReceiverOffset));
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm,
|
||||
Handle<JSFunction> setter) {
|
||||
|
@ -8704,23 +8704,12 @@ TEST(DetachGlobal) {
|
||||
}
|
||||
|
||||
|
||||
void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
info.GetReturnValue().Set(
|
||||
info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
|
||||
}
|
||||
|
||||
|
||||
TEST(DetachedAccesses) {
|
||||
LocalContext env1;
|
||||
v8::HandleScope scope(env1->GetIsolate());
|
||||
|
||||
// Create second environment.
|
||||
Local<ObjectTemplate> inner_global_template =
|
||||
FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
|
||||
inner_global_template ->SetAccessorProperty(
|
||||
v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
|
||||
v8::Local<Context> env2 =
|
||||
Context::New(env1->GetIsolate(), NULL, inner_global_template);
|
||||
v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
|
||||
|
||||
Local<Value> foo = v8_str("foo");
|
||||
|
||||
@ -8728,21 +8717,15 @@ TEST(DetachedAccesses) {
|
||||
env1->SetSecurityToken(foo);
|
||||
env2->SetSecurityToken(foo);
|
||||
|
||||
env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
|
||||
|
||||
{
|
||||
v8::Context::Scope scope(env2);
|
||||
env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
|
||||
CompileRun(
|
||||
"function bound_x() { return x; }"
|
||||
"function get_x() { return this.x; }"
|
||||
"function get_x_w() { return (function() {return this.x;})(); }");
|
||||
env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
|
||||
"var x = 'x';"
|
||||
"function get_x() { return this.x; }"
|
||||
"function get_x_w() { return get_x(); }"
|
||||
"");
|
||||
env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
|
||||
env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
|
||||
env1->Global()->Set(
|
||||
v8_str("this_x"),
|
||||
CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
|
||||
}
|
||||
|
||||
Local<Object> env2_global = env2->Global();
|
||||
@ -8750,14 +8733,10 @@ TEST(DetachedAccesses) {
|
||||
env2->DetachGlobal();
|
||||
|
||||
Local<Value> result;
|
||||
result = CompileRun("bound_x()");
|
||||
CHECK_EQ(v8_str("env2_x"), result);
|
||||
result = CompileRun("get_x()");
|
||||
CHECK(result->IsUndefined());
|
||||
result = CompileRun("get_x_w()");
|
||||
CHECK(result->IsUndefined());
|
||||
result = CompileRun("this_x()");
|
||||
CHECK_EQ(v8_str("env2_x"), result);
|
||||
|
||||
// Reattach env2's proxy
|
||||
env2 = Context::New(env1->GetIsolate(),
|
||||
@ -8767,62 +8746,13 @@ TEST(DetachedAccesses) {
|
||||
env2->SetSecurityToken(foo);
|
||||
{
|
||||
v8::Context::Scope scope(env2);
|
||||
env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
|
||||
env2->Global()->Set(v8_str("env1"), env1->Global());
|
||||
result = CompileRun(
|
||||
"results = [];"
|
||||
"for (var i = 0; i < 4; i++ ) {"
|
||||
" results.push(env1.bound_x());"
|
||||
" results.push(env1.get_x());"
|
||||
" results.push(env1.get_x_w());"
|
||||
" results.push(env1.this_x());"
|
||||
"}"
|
||||
"results");
|
||||
Local<v8::Array> results = Local<v8::Array>::Cast(result);
|
||||
CHECK_EQ(16, results->Length());
|
||||
for (int i = 0; i < 16; i += 4) {
|
||||
CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
|
||||
CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
|
||||
CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
|
||||
CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
|
||||
}
|
||||
CompileRun("var x = 'x2';");
|
||||
}
|
||||
|
||||
result = CompileRun(
|
||||
"results = [];"
|
||||
"for (var i = 0; i < 4; i++ ) {"
|
||||
" results.push(bound_x());"
|
||||
" results.push(get_x());"
|
||||
" results.push(get_x_w());"
|
||||
" results.push(this_x());"
|
||||
"}"
|
||||
"results");
|
||||
Local<v8::Array> results = Local<v8::Array>::Cast(result);
|
||||
CHECK_EQ(16, results->Length());
|
||||
for (int i = 0; i < 16; i += 4) {
|
||||
CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
|
||||
CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
|
||||
CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
|
||||
CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
|
||||
}
|
||||
|
||||
result = CompileRun(
|
||||
"results = [];"
|
||||
"for (var i = 0; i < 4; i++ ) {"
|
||||
" results.push(this.bound_x());"
|
||||
" results.push(this.get_x());"
|
||||
" results.push(this.get_x_w());"
|
||||
" results.push(this.this_x());"
|
||||
"}"
|
||||
"results");
|
||||
results = Local<v8::Array>::Cast(result);
|
||||
CHECK_EQ(16, results->Length());
|
||||
for (int i = 0; i < 16; i += 4) {
|
||||
CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
|
||||
CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
|
||||
CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
|
||||
CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
|
||||
}
|
||||
result = CompileRun("get_x()");
|
||||
CHECK(result->IsUndefined());
|
||||
result = CompileRun("get_x_w()");
|
||||
CHECK_EQ(v8_str("x2"), result);
|
||||
}
|
||||
|
||||
|
||||
@ -20180,10 +20110,11 @@ THREADED_TEST(ForeignFunctionReceiver) {
|
||||
CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
|
||||
CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
|
||||
|
||||
// TODO(1547): Make the following also return "i".
|
||||
// Calling with environment record as base.
|
||||
TestReceiver(i, foreign_context->Global(), "func()");
|
||||
TestReceiver(o, context->Global(), "func()");
|
||||
// Calling with no base.
|
||||
TestReceiver(i, foreign_context->Global(), "(1,func)()");
|
||||
TestReceiver(o, context->Global(), "(1,func)()");
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,103 +0,0 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
var realms = [Realm.current(), Realm.create()];
|
||||
globals = [Realm.global(0), Realm.global(1)];
|
||||
Realm.shared = {}
|
||||
|
||||
function install(name, value) {
|
||||
Realm.shared[name] = value;
|
||||
for (i in realms) {
|
||||
Realm.eval(realms[i], name + " = Realm.shared['" + name + "'];");
|
||||
}
|
||||
}
|
||||
|
||||
install('return_this', function() { return this; });
|
||||
install('return_this_strict', function () { 'use strict'; return this; });
|
||||
|
||||
// test behaviour of 'with' scope
|
||||
for (i in realms) {
|
||||
Realm.shared.results = [];
|
||||
// in the second case, 'this' is found in the with scope,
|
||||
// so the receiver is 'this'
|
||||
Realm.eval(realms[i]," \
|
||||
with('irrelevant') { \
|
||||
Realm.shared.results.push(return_this()); \
|
||||
Realm.shared.results.push(return_this_strict()); \
|
||||
} \
|
||||
with(this) { \
|
||||
Realm.shared.results.push(return_this()); \
|
||||
Realm.shared.results.push(return_this_strict()); \
|
||||
} \
|
||||
");
|
||||
assertSame(globals[0], Realm.shared.results[0]);
|
||||
assertSame(undefined, Realm.shared.results[1]);
|
||||
assertSame(globals[i], Realm.shared.results[2]);
|
||||
assertSame(globals[i], Realm.shared.results[3]);
|
||||
}
|
||||
|
||||
// test 'apply' and 'call'
|
||||
for (i in realms) {
|
||||
// 'apply' without a receiver is a contextual call
|
||||
assertSame(globals[0], Realm.eval(realms[i],'return_this.apply()')) ;
|
||||
assertSame(undefined, Realm.eval(realms[i],'return_this_strict.apply()'));
|
||||
assertSame(globals[0], Realm.eval(realms[i],'return_this.apply(null)')) ;
|
||||
assertSame(null, Realm.eval(realms[i],'return_this_strict.apply(null)'));
|
||||
// 'call' without a receiver is a contextual call
|
||||
assertSame(globals[0], Realm.eval(realms[i],'return_this.call()')) ;
|
||||
assertSame(undefined, Realm.eval(realms[i],'return_this_strict.call()'));
|
||||
assertSame(globals[0], Realm.eval(realms[i],'return_this.call(null)')) ;
|
||||
assertSame(null, Realm.eval(realms[i],'return_this_strict.call(null)'));
|
||||
}
|
||||
|
||||
// test ics
|
||||
for (var i = 0; i < 4; i++) {
|
||||
assertSame(globals[0], return_this());
|
||||
assertSame(undefined, return_this_strict());
|
||||
}
|
||||
|
||||
// BUG(1547)
|
||||
|
||||
Realm.eval(realms[0], "var name = 'o'");
|
||||
Realm.eval(realms[1], "var name = 'i'");
|
||||
|
||||
install('f', function() { return this.name; });
|
||||
install('g', function() { "use strict"; return this ? this.name : "u"; });
|
||||
|
||||
for (i in realms) {
|
||||
result = Realm.eval(realms[i], " \
|
||||
(function(){return f();})() + \
|
||||
(function(){return (1,f)();})() + \
|
||||
(function(){'use strict'; return f();})() + \
|
||||
(function(){'use strict'; return (1,f)();})() + \
|
||||
(function(){return g();})() + \
|
||||
(function(){return (1,g)();})() + \
|
||||
(function(){'use strict'; return g();})() + \
|
||||
(function(){'use strict'; return (1,g)();})(); \
|
||||
");
|
||||
assertSame("oooouuuu", result);
|
||||
}
|
@ -53,7 +53,8 @@ var receiver
|
||||
|
||||
function TestCall(isStrict, callTrap) {
|
||||
assertEquals(42, callTrap(5, 37))
|
||||
assertSame(isStrict ? undefined : global_object, receiver)
|
||||
// TODO(rossberg): strict mode seems to be broken on x64...
|
||||
// assertSame(isStrict ? undefined : global_object, receiver)
|
||||
|
||||
var handler = {
|
||||
get: function(r, k) {
|
||||
@ -66,7 +67,8 @@ function TestCall(isStrict, callTrap) {
|
||||
|
||||
receiver = 333
|
||||
assertEquals(42, f(11, 31))
|
||||
assertSame(isStrict ? undefined : global_object, receiver)
|
||||
// TODO(rossberg): strict mode seems to be broken on x64...
|
||||
// assertSame(isStrict ? undefined : global_object, receiver)
|
||||
receiver = 333
|
||||
assertEquals(42, o.f(10, 32))
|
||||
assertSame(o, receiver)
|
||||
@ -744,31 +746,3 @@ function TestCalls() {
|
||||
|
||||
TestCalls()
|
||||
*/
|
||||
|
||||
var realms = [Realm.create(), Realm.create()];
|
||||
Realm.shared = {};
|
||||
|
||||
Realm.eval(realms[0], "function f() { return this; };");
|
||||
Realm.eval(realms[0], "Realm.shared.f = f;");
|
||||
Realm.eval(realms[0], "Realm.shared.fg = this;");
|
||||
Realm.eval(realms[1], "function g() { return this; };");
|
||||
Realm.eval(realms[1], "Realm.shared.g = g;");
|
||||
Realm.eval(realms[1], "Realm.shared.gg = this;");
|
||||
|
||||
var fp = Proxy.createFunction({}, Realm.shared.f);
|
||||
var gp = Proxy.createFunction({}, Realm.shared.g);
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
assertEquals(Realm.shared.fg, fp());
|
||||
assertEquals(Realm.shared.gg, gp());
|
||||
|
||||
with (this) {
|
||||
assertEquals(Realm.shared.fg, fp());
|
||||
assertEquals(Realm.shared.gg, gp());
|
||||
}
|
||||
|
||||
with ({}) {
|
||||
assertEquals(Realm.shared.fg, fp());
|
||||
assertEquals(Realm.shared.gg, gp());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user