Version 3.24.11
Remove generated makefiles on linux when running gyp_v8 (Chromium issue 331475)
Fix building d8 with readline support due to API changes
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@18467 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index c095881..f5d43b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2014-01-07: Version 3.24.11
+
+ Remove generated makefiles on linux when running gyp_v8
+ (Chromium issue 331475)
+
+ Fix building d8 with readline support due to API changes
+
+ Performance and stability improvements on all platforms.
+
+
2014-01-03: Version 3.24.10
Reland r18383: More API cleanup (Chromium issue 324225).
diff --git a/build/gyp_v8 b/build/gyp_v8
index ddf88ce..f2a60d1 100755
--- a/build/gyp_v8
+++ b/build/gyp_v8
@@ -159,6 +159,9 @@
# Generate for the architectures supported on the given platform.
gyp_args = list(args)
if platform.system() == 'Linux':
+ # Work around for crbug.com/331475.
+ for f in glob.glob(os.path.join(v8_root, 'out', 'Makefile.*')):
+ os.unlink(f)
# --generator-output defines where the Makefile goes.
gyp_args.append('--generator-output=out')
# -Goutput_dir defines where the build output goes, relative to the
diff --git a/include/v8.h b/include/v8.h
index c073fb3..1771969 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -738,7 +738,7 @@
template<class T>
class UniquePersistent : public PersistentBase<T> {
struct RValue {
- V8_INLINE explicit RValue(UniquePersistent* object) : object(object) {}
+ V8_INLINE explicit RValue(UniquePersistent* obj) : object(obj) {}
UniquePersistent* object;
};
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 5a47ef4..6c374b3 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -34,6 +34,7 @@
#include "deoptimizer.h"
#include "full-codegen.h"
#include "runtime.h"
+#include "stub-cache.h"
namespace v8 {
namespace internal {
@@ -1091,12 +1092,8 @@
// Use the global receiver object from the called function as the
// receiver.
__ bind(&use_global_receiver);
- 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));
+ __ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+ __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
__ bind(&patch_receiver);
__ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
@@ -1287,11 +1284,7 @@
// Use the current global receiver object as the receiver.
__ bind(&use_global_receiver);
- 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, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
// Push the receiver.
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index f70271b..8af47b7 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -3182,31 +3182,47 @@
// r2 : cache cell for call target
Label slow, 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()) {
- 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.
- __ ldr(r3,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalReceiverOffset));
- __ str(r3, MemOperand(sp, argc_ * kPointerSize));
- __ bind(&call);
- }
-
// 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);
+
+ // 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);
+ }
+ // 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);
+ __ str(r3, MemOperand(sp, argc_ * kPointerSize));
+ __ jmp(&call);
+
+ __ bind(&patch_current_context);
+ __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
+ __ str(r4, 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);
+ }
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm);
@@ -3251,7 +3267,7 @@
__ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32));
__ mov(r2, Operand::Zero());
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
- __ SetCallKind(r5, CALL_AS_METHOD);
+ __ SetCallKind(r5, CALL_AS_FUNCTION);
{
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index b362f12..da7eb99 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -2815,12 +2815,12 @@
{ PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(callee);
}
- // Load global receiver object.
- __ ldr(r1, GlobalObjectOperand());
- __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
+ // Push the hole as receiver.
+ // It will be correctly replaced in the call stub.
+ __ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
__ push(r1);
// Emit function call.
- EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
+ EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
}
#ifdef DEBUG
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index ea247b3..a8943e1 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -491,7 +491,7 @@
// Patch the receiver on the stack.
__ bind(&global);
- __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
+ CallStubCompiler::FetchGlobalProxy(masm, r2, r1);
__ str(r2, MemOperand(sp, argc * kPointerSize));
__ bind(&invoke);
}
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 0463ce4..c58fdb1 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -3491,11 +3491,8 @@
__ 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 {
@@ -3993,7 +3990,10 @@
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
- CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
+ CallFunctionFlags flags =
+ instr->hydrogen()->IsContextualCall() ?
+ RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
+ CallFunctionStub stub(arity, flags);
if (instr->hydrogen()->IsTailCall()) {
if (NeedsEagerFrame()) __ mov(sp, fp);
__ Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 4d9fc0d..5350b6b 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -2341,11 +2341,23 @@
}
-void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
+void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
+ Handle<JSFunction> function) {
if (object->IsGlobalObject()) {
const int argc = arguments().immediate();
const int receiver_offset = argc * kPointerSize;
- __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
+ __ 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;
__ str(r3, MemOperand(sp, receiver_offset));
}
}
@@ -2444,7 +2456,7 @@
ASSERT(function.is(r1));
// Check that the function really is a function.
GenerateFunctionCheck(function, r3, miss);
- PatchGlobalProxy(object);
+ PatchGlobalProxy(object, function);
// Invoke the function.
__ InvokeFunction(r1, arguments(), JUMP_FUNCTION,
@@ -2562,6 +2574,15 @@
#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) {
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index f27ca7a..7b8af06 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1669,6 +1669,8 @@
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
@@ -1682,6 +1684,11 @@
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())->
@@ -2581,6 +2588,8 @@
HookUpGlobalProxy(inner_global, global_proxy);
HookUpInnerGlobal(inner_global);
+ native_context()->builtins()->set_global_receiver(
+ native_context()->global_proxy());
if (!ConfigureGlobalObjects(global_template)) return;
} else {
diff --git a/src/code-stubs.h b/src/code-stubs.h
index bb9ff78..3c3c194 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -1550,8 +1550,8 @@
virtual void PrintName(StringStream* stream);
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
- class FlagBits: public BitField<CallFunctionFlags, 0, 2> {};
- class ArgcBits: public BitField<unsigned, 2, 32 - 2> {};
+ class FlagBits: public BitField<CallFunctionFlags, 0, 3> {};
+ class ArgcBits: public BitField<unsigned, 3, 32 - 3> {};
Major MajorKey() { return CallFunction; }
int MinorKey() {
@@ -1563,6 +1563,10 @@
return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
}
+ bool ReceiverIsImplicit() {
+ return (flags_ & RECEIVER_IS_IMPLICIT) != 0;
+ }
+
bool RecordCallTarget() {
return (flags_ & RECORD_CALL_TARGET) != 0;
}
diff --git a/src/d8-debug.cc b/src/d8-debug.cc
index 0cd1cc2..2c909fa 100644
--- a/src/d8-debug.cc
+++ b/src/d8-debug.cc
@@ -30,6 +30,7 @@
#include "d8.h"
#include "d8-debug.h"
#include "debug-agent.h"
+#include "platform/socket.h"
namespace v8 {
diff --git a/src/d8-readline.cc b/src/d8-readline.cc
index 15b1361..42cb0c5 100644
--- a/src/d8-readline.cc
+++ b/src/d8-readline.cc
@@ -163,7 +163,7 @@
completions = Local<Array>::New(isolate, current_completions);
}
if (current_index < completions->Length()) {
- Handle<Integer> index = Integer::New(current_index);
+ Handle<Integer> index = Integer::New(isolate, current_index);
Handle<Value> str_obj = completions->Get(index);
current_index++;
String::Utf8Value str(str_obj);
diff --git a/src/debug.h b/src/debug.h
index d1b3b23..564f9e8 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -38,7 +38,6 @@
#include "frames-inl.h"
#include "hashmap.h"
#include "platform.h"
-#include "platform/socket.h"
#include "string-stream.h"
#include "v8threads.h"
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index a32a418..71ae304 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -2414,7 +2414,8 @@
enum CallMode {
NORMAL_CALL,
- TAIL_CALL
+ TAIL_CALL,
+ NORMAL_CONTEXTUAL_CALL
};
@@ -2425,7 +2426,7 @@
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(); }
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 7bdc02f..03e666c 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -7618,6 +7618,27 @@
}
+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);
@@ -7738,13 +7759,11 @@
HValue* function = Pop();
Add<HCheckValue>(function, expr->target());
- // 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.
+ // Install global receiver on stack.
const int receiver_index = argument_count - 1;
ASSERT(environment()->ExpressionStackAt(receiver_index)->
IsGlobalObject());
- environment()->SetExpressionStackAt(receiver_index, global_receiver);
+ InstallGlobalReceiverInExpressionStack(receiver_index, expr->target());
if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop.
if (FLAG_trace_inlining) {
@@ -7761,9 +7780,12 @@
}
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<HCallNamed>(var->name(), argument_count));
+ call = PreProcessCall(New<HCallGlobal>(var->name(), argument_count));
} else {
call = PreProcessCall(New<HCallKnownGlobal>(
expr->target(), argument_count));
@@ -7788,6 +7810,12 @@
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 ");
@@ -7808,12 +7836,11 @@
} else {
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* function = Top();
- HGlobalObject* global_object = Add<HGlobalObject>();
- HGlobalReceiver* receiver = Add<HGlobalReceiver>(global_object);
+ HValue* receiver = graph()->GetConstantHole();
Push(Add<HPushArgument>(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
-
- call = New<HCallFunction>(function, argument_count);
+ call = New<HCallFunction>(
+ function, argument_count, NORMAL_CONTEXTUAL_CALL);
Drop(argument_count + 1);
}
}
diff --git a/src/hydrogen.h b/src/hydrogen.h
index ca3fb43..2af2469 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -2502,6 +2502,9 @@
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_;
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index 1f73a7d..67503e3 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -32,6 +32,7 @@
#include "codegen.h"
#include "deoptimizer.h"
#include "full-codegen.h"
+#include "stub-cache.h"
namespace v8 {
namespace internal {
@@ -783,12 +784,7 @@
// Use the global receiver object from the called function as the
// receiver.
__ bind(&use_global_receiver);
- 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));
+ CallStubCompiler::FetchGlobalProxy(masm, ebx, edi);
__ bind(&patch_receiver);
__ mov(Operand(esp, eax, times_4, 0), ebx);
@@ -961,12 +957,7 @@
// Use the current global receiver object as the receiver.
__ bind(&use_global_receiver);
- 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));
+ CallStubCompiler::FetchGlobalProxy(masm, ebx, edi);
// Push the receiver.
__ bind(&push_receiver);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 305a6d8..2ba08c5 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -2517,29 +2517,46 @@
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()) {
- 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);
+ 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);
+ }
// Patch the receiver on the stack with the global receiver object.
- __ mov(ecx, GlobalObjectOperand());
- __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
+ // 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(Operand(esp, (argc_ + 1) * kPointerSize), ecx);
- __ bind(&receiver_ok);
- }
+ __ jmp(&call, Label::kNear);
- // 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);
+ __ 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);
+ }
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm);
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index e43e525..d3b1dd8 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -2769,11 +2769,11 @@
{ PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(callee);
}
- // Load global receiver object.
- __ mov(ebx, GlobalObjectOperand());
- __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
+ // Push the hole as receiver.
+ // It will be correctly replaced in the call stub.
+ __ push(Immediate(isolate()->factory()->the_hole_value()));
// Emit function call.
- EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
+ EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
}
#ifdef DEBUG
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 2973beb..4db8802 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1112,8 +1112,9 @@
// Patch the receiver on the stack.
__ bind(&global);
- __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ CallStubCompiler::FetchGlobalProxy(masm, edx, edi);
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+
__ bind(&invoke);
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 1a20fc3..ade9ee3 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -3675,10 +3675,7 @@
// 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.
- __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
- __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
- __ mov(receiver,
- FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
+ CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
__ bind(&receiver_ok);
}
@@ -4245,7 +4242,10 @@
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
+ CallFunctionFlags flags =
+ instr->hydrogen()->IsContextualCall() ?
+ RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
+ CallFunctionStub stub(arity, flags);
if (instr->hydrogen()->IsTailCall()) {
if (NeedsEagerFrame()) __ leave();
__ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 6e720f1..6bf6179 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1166,7 +1166,7 @@
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
LOperand* receiver = UseRegister(instr->receiver());
- LOperand* function = UseRegisterAtStart(instr->function());
+ LOperand* function = UseRegister(instr->function());
LOperand* temp = TempRegister();
LWrapReceiver* result =
new(zone()) LWrapReceiver(receiver, function, temp);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 6ab3964..d63c2bb 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -2468,11 +2468,23 @@
}
-void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
+void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
+ Handle<JSFunction> function) {
if (object->IsGlobalObject()) {
const int argc = arguments().immediate();
const int receiver_offset = (argc + 1) * kPointerSize;
- __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ __ 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(Operand(esp, receiver_offset), edx);
}
}
@@ -2566,7 +2578,7 @@
GenerateFunctionCheck(function, ebx, miss);
if (!function.is(edi)) __ mov(edi, function);
- PatchGlobalProxy(object);
+ PatchGlobalProxy(object, function);
// Invoke the function.
__ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
@@ -2681,6 +2693,15 @@
#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) {
diff --git a/src/runtime.cc b/src/runtime.cc
index 713d450..281c650 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -6525,7 +6525,7 @@
if (!maybe_o->ToObject(&o)) return maybe_o;
}
SeqOneByteString* result = SeqOneByteString::cast(o);
- bool has_changed_character;
+ bool has_changed_character = false;
bool is_ascii = FastAsciiConvert<Converter>(
reinterpret_cast<char*>(result->GetChars()),
reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
@@ -9252,7 +9252,7 @@
// GetProperty below can cause GC.
Handle<Object> receiver_handle(
object->IsGlobalObject()
- ? GlobalObject::cast(*object)->global_receiver()
+ ? Object::cast(isolate->heap()->the_hole_value())
: object->IsJSProxy() ? static_cast<Object*>(*object)
: ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
isolate);
diff --git a/src/runtime.js b/src/runtime.js
index 35bc07a..2a949ae 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -48,7 +48,6 @@
var $Function = global.Function;
var $Boolean = global.Boolean;
var $NaN = %GetRootNaN();
-var builtins = this;
// ECMA-262 Section 11.9.3.
function EQUALS(y) {
diff --git a/src/spaces.cc b/src/spaces.cc
index ee19a02..70e482f 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -1079,12 +1079,7 @@
// upgraded to handle small pages.
size = AreaSize();
} else {
-#if V8_TARGET_ARCH_MIPS
- // TODO(plind): Investigate larger code stubs size on MIPS.
size = 480 * KB;
-#else
- size = 416 * KB;
-#endif
}
break;
default:
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index dc2c340..e8b94f1 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -1155,7 +1155,7 @@
void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
Handle<JSFunction> function) {
- PatchGlobalProxy(object);
+ PatchGlobalProxy(object, function);
GenerateJumpFunctionIgnoreReceiver(function);
}
@@ -1163,7 +1163,7 @@
void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
Register actual_closure,
Handle<JSFunction> function) {
- PatchGlobalProxy(object);
+ PatchGlobalProxy(object, function);
ParameterCount expected(function);
__ InvokeFunction(actual_closure, expected, arguments(),
JUMP_FUNCTION, NullCallWrapper(), call_kind());
diff --git a/src/stub-cache.h b/src/stub-cache.h
index ebf0bd3..0cf9e8f 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -912,7 +912,11 @@
// Patch the global proxy over the global object if the global object is the
// receiver.
- void PatchGlobalProxy(Handle<Object> object);
+ static void FetchGlobalProxy(MacroAssembler* masm,
+ Register target,
+ Register function);
+ void PatchGlobalProxy(Handle<Object> object, Register function);
+ void PatchGlobalProxy(Handle<Object> object, Handle<JSFunction> function);
// Returns the register containing the holder of |name|.
Register HandlerFrontendHeader(Handle<Object> object,
diff --git a/src/v8globals.h b/src/v8globals.h
index a9980e5..da290b2 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -293,8 +293,10 @@
// 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 << 1
+ RECORD_CALL_TARGET = 1 << 2
};
diff --git a/src/version.cc b/src/version.cc
index db263a8..3e0bf84 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 24
-#define BUILD_NUMBER 10
+#define BUILD_NUMBER 11
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 7803073..b2cd558 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -32,6 +32,7 @@
#include "codegen.h"
#include "deoptimizer.h"
#include "full-codegen.h"
+#include "stub-cache.h"
namespace v8 {
namespace internal {
@@ -846,12 +847,7 @@
// Use the global receiver object from the called function as the
// receiver.
__ bind(&use_global_receiver);
- 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));
+ CallStubCompiler::FetchGlobalProxy(masm, rbx, rdi);
__ bind(&patch_receiver);
__ movq(args.GetArgumentOperand(1), rbx);
@@ -1031,13 +1027,7 @@
// Use the current global receiver object as the receiver.
__ bind(&use_global_receiver);
- 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));
-
+ CallStubCompiler::FetchGlobalProxy(masm, rbx, rdi);
// Push the receiver.
__ bind(&push_receiver);
__ push(rbx);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 920843d..b8e783d 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -2350,28 +2350,45 @@
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()) {
- 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);
+ 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);
+ }
// Patch the receiver on the stack with the global receiver object.
- __ movq(rcx, GlobalObjectOperand());
- __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
+ // 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(args.GetReceiverOperand(), rcx);
- __ bind(&call);
- }
+ __ jmp(&call, Label::kNear);
- // 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);
+ __ 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);
+ }
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm);
@@ -2414,7 +2431,7 @@
__ PushReturnAddressFrom(rcx);
__ Set(rax, argc_ + 1);
__ Set(rbx, 0);
- __ SetCallKind(rcx, CALL_AS_METHOD);
+ __ SetCallKind(rcx, CALL_AS_FUNCTION);
__ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
{
Handle<Code> adaptor =
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index a56f223..99206b9 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -2746,11 +2746,11 @@
{ PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(callee);
}
- // Load global receiver object.
- __ movq(rbx, GlobalObjectOperand());
- __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
+ // Push the hole as receiver.
+ // It will be correctly replaced in the call stub.
+ __ PushRoot(Heap::kTheHoleValueRootIndex);
// Emit function call.
- EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
+ EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
}
#ifdef DEBUG
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 9448d37..b2d33e0 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -998,7 +998,7 @@
// Patch the receiver on the stack.
__ bind(&global);
- __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ CallStubCompiler::FetchGlobalProxy(masm, rdx, rdi);
__ movq(args.GetReceiverOperand(), rdx);
__ bind(&invoke);
}
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index d35219c..e6a20f2 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -3250,10 +3250,7 @@
// 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.
- __ movq(receiver, Operand(rbp, StandardFrameConstants::kContextOffset));
- __ movq(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
- __ movq(receiver,
- FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
+ CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
__ bind(&receiver_ok);
}
@@ -3818,7 +3815,10 @@
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
+ CallFunctionFlags flags =
+ instr->hydrogen()->IsContextualCall() ?
+ RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
+ CallFunctionStub stub(arity, flags);
if (instr->hydrogen()->IsTailCall()) {
if (NeedsEagerFrame()) __ leave();
__ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 950ee28..3bbe1fc 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -2378,10 +2378,21 @@
}
-void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
+void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
+ Handle<JSFunction> function) {
if (object->IsGlobalObject()) {
StackArgumentsAccessor args(rsp, arguments());
- __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ __ 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(args.GetReceiverOperand(), rdx);
}
}
@@ -2475,7 +2486,7 @@
GenerateFunctionCheck(function, rbx, miss);
if (!function.is(rdi)) __ movq(rdi, function);
- PatchGlobalProxy(object);
+ PatchGlobalProxy(object, function);
// Invoke the function.
__ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
@@ -2588,6 +2599,15 @@
#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) {
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index eeb7865..372c70d 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -8704,12 +8704,23 @@
}
+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.
- v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
+ 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);
Local<Value> foo = v8_str("foo");
@@ -8717,15 +8728,21 @@
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(
- "var x = 'x';"
- "function get_x() { return this.x; }"
- "function get_x_w() { return get_x(); }"
- "");
+ "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"));
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();
@@ -8733,10 +8750,14 @@
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(),
@@ -8746,13 +8767,62 @@
env2->SetSecurityToken(foo);
{
v8::Context::Scope scope(env2);
- CompileRun("var x = 'x2';");
+ 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));
+ }
}
- result = CompileRun("get_x()");
- CHECK(result->IsUndefined());
- result = CompileRun("get_x_w()");
- CHECK_EQ(v8_str("x2"), result);
+ 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));
+ }
}
@@ -20110,11 +20180,10 @@
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(o, context->Global(), "func()");
+ TestReceiver(i, foreign_context->Global(), "func()");
// Calling with no base.
- TestReceiver(o, context->Global(), "(1,func)()");
+ TestReceiver(i, foreign_context->Global(), "(1,func)()");
}
diff --git a/test/mjsunit/contextual-calls.js b/test/mjsunit/contextual-calls.js
new file mode 100644
index 0000000..10c3e8d
--- /dev/null
+++ b/test/mjsunit/contextual-calls.js
@@ -0,0 +1,103 @@
+// 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);
+}
diff --git a/test/mjsunit/harmony/proxies-function.js b/test/mjsunit/harmony/proxies-function.js
index 6b8d098..8c91e9b 100644
--- a/test/mjsunit/harmony/proxies-function.js
+++ b/test/mjsunit/harmony/proxies-function.js
@@ -53,8 +53,7 @@
function TestCall(isStrict, callTrap) {
assertEquals(42, callTrap(5, 37))
- // TODO(rossberg): strict mode seems to be broken on x64...
- // assertSame(isStrict ? undefined : global_object, receiver)
+ assertSame(isStrict ? undefined : global_object, receiver)
var handler = {
get: function(r, k) {
@@ -67,8 +66,7 @@
receiver = 333
assertEquals(42, f(11, 31))
- // TODO(rossberg): strict mode seems to be broken on x64...
- // assertSame(isStrict ? undefined : global_object, receiver)
+ assertSame(isStrict ? undefined : global_object, receiver)
receiver = 333
assertEquals(42, o.f(10, 32))
assertSame(o, receiver)
@@ -746,3 +744,31 @@
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());
+ }
+}