Revision: 9030
Author: [email protected]
Date: Fri Aug 26 06:53:00 2011
Log: Make (some) functions called from builtin functions use the
callback's global as receiver.
Changes GetGlobalReceiver() to GetDefaultReceiver(func) that returns
undefined
for strict and native functions, and the function's context's global proxy
for "normal" functions.
BUG=v8:1547
TEST=cctest/api-test/ForeignFunctionReceiver
Review URL: http://codereview.chromium.org/7741042
http://code.google.com/p/v8/source/detail?r=9030
Modified:
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/array.js
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/mips/full-codegen-mips.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/runtime.h
/branches/bleeding_edge/src/string.js
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Aug 23 05:00:09
2011
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Aug 26 06:53:00
2011
@@ -3578,39 +3578,6 @@
__ bind(&done);
context()->Plug(r0);
}
-
-
-void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>*
args) {
- ASSERT(args->length() == 1);
-
- // Load the function into r0.
- VisitForAccumulatorValue(args->at(0));
-
- // Prepare for the test.
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- // Test for strict mode function.
- __ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
- __ ldr(r1, FieldMemOperand(r1,
SharedFunctionInfo::kCompilerHintsOffset));
- __ tst(r1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
- kSmiTagSize)));
- __ b(ne, if_true);
-
- // Test for native function.
- __ tst(r1, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
- __ b(ne, if_true);
-
- // Not native or strict-mode function.
- __ b(if_false);
-
- PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- context()->Plug(if_true, if_false);
-}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
=======================================
--- /branches/bleeding_edge/src/array.js Fri Jul 15 04:07:18 2011
+++ /branches/bleeding_edge/src/array.js Fri Aug 26 06:53:00 2011
@@ -742,8 +742,7 @@
else return x < y ? -1 : 1;
};
}
- var receiver =
- %_IsNativeOrStrictMode(comparefn) ? void 0 : %GetGlobalReceiver();
+ var receiver = %GetDefaultReceiver(comparefn);
function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Tue Aug 23 04:19:08 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Fri Aug 26 06:53:00 2011
@@ -6220,11 +6220,6 @@
void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
return Bailout("inlined runtime function: FastAsciiArrayJoin");
}
-
-
-void HGraphBuilder::GenerateIsNativeOrStrictMode(CallRuntime* call) {
- return Bailout("inlined runtime function: IsNativeOrStrictMode");
-}
#undef CHECK_BAILOUT
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Aug 19
02:54:08 2011
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Aug 26
06:53:00 2011
@@ -3631,39 +3631,6 @@
decrement_stack_height();
context()->Plug(eax);
}
-
-
-void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>*
args) {
- ASSERT(args->length() == 1);
-
- // Load the function into eax.
- VisitForAccumulatorValue(args->at(0));
-
- // Prepare for the test.
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- // Test for strict mode function.
- __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
- __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
- 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
- __ j(not_equal, if_true);
-
- // Test for native function.
- __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
- 1 << SharedFunctionInfo::kNativeBitWithinByte);
- __ j(not_equal, if_true);
-
- // Not native or strict-mode function.
- __ jmp(if_false);
-
- PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- context()->Plug(if_true, if_false);
-}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
=======================================
--- /branches/bleeding_edge/src/mips/full-codegen-mips.cc Mon Aug 22
02:05:28 2011
+++ /branches/bleeding_edge/src/mips/full-codegen-mips.cc Fri Aug 26
06:53:00 2011
@@ -3600,39 +3600,6 @@
__ bind(&done);
context()->Plug(v0);
}
-
-
-void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>*
args) {
- ASSERT(args->length() == 1);
-
- // Load the function into v0.
- VisitForAccumulatorValue(args->at(0));
-
- // Prepare for the test.
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- // Test for strict mode function.
- __ lw(a1, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
- __ lw(a1, FieldMemOperand(a1, SharedFunctionInfo::kCompilerHintsOffset));
- __ And(at, a1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
- kSmiTagSize)));
- __ Branch(if_true, ne, at, Operand(zero_reg));
-
- // Test for native function.
- __ And(at, a1, Operand(1 << (SharedFunctionInfo::kNative +
kSmiTagSize)));
- __ Branch(if_true, ne, at, Operand(zero_reg));
-
- // Not native or strict-mode function.
- __ Branch(if_false);
-
- PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- context()->Plug(if_true, if_false);
-}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri Aug 26 06:03:30 2011
+++ /branches/bleeding_edge/src/runtime.cc Fri Aug 26 06:53:00 2011
@@ -1866,10 +1866,19 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
- // Returns a real global receiver, not one of builtins object.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
+ NoHandleAllocation handle_free;
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSFunction, function, args[0]);
+ SharedFunctionInfo* shared = function->shared();
+ if (shared->native() || shared->strict_mode()) {
+ return isolate->heap()->undefined_value();
+ }
+ // Returns undefined for strict or native functions, or
+ // the associated global receiver for "normal" functions.
+
Context* global_context =
- isolate->context()->global()->global_context();
+ function->context()->global()->global_context();
return global_context->global()->global_receiver();
}
=======================================
--- /branches/bleeding_edge/src/runtime.h Thu Aug 11 09:29:28 2011
+++ /branches/bleeding_edge/src/runtime.h Fri Aug 26 06:53:00 2011
@@ -65,7 +65,7 @@
F(ToSlowProperties, 1, 1) \
F(FinishArrayPrototypeSetup, 1, 1) \
F(SpecialArrayFunctions, 1, 1) \
- F(GetGlobalReceiver, 0, 1) \
+ F(GetDefaultReceiver, 1, 1) \
\
F(GetPrototype, 1, 1) \
F(IsInPrototypeChain, 2, 1) \
@@ -491,8 +491,7 @@
F(IsRegExpEquivalent, 2,
1) \
F(HasCachedArrayIndex, 1,
1) \
F(GetCachedArrayIndex, 1,
1) \
- F(FastAsciiArrayJoin, 2,
1) \
- F(IsNativeOrStrictMode, 1, 1)
+ F(FastAsciiArrayJoin, 2, 1)
//
----------------------------------------------------------------------------
=======================================
--- /branches/bleeding_edge/src/string.js Mon Aug 22 06:55:25 2011
+++ /branches/bleeding_edge/src/string.js Fri Aug 26 06:53:00 2011
@@ -251,8 +251,7 @@
// Compute the string to replace with.
if (IS_FUNCTION(replace)) {
- var receiver =
- %_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
+ var receiver = %GetDefaultReceiver(replace);
builder.add(%_CallFunction(receiver,
search,
start,
@@ -420,8 +419,7 @@
if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
var match_start = 0;
var override = new InternalArray(null, 0, subject);
- var receiver =
- %_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
+ var receiver = %GetDefaultReceiver(replace);
while (i < len) {
var elem = res[i];
if (%_IsSmi(elem)) {
@@ -478,8 +476,7 @@
// No captures, only the match, which is always valid.
var s = SubString(subject, index, endOfMatch);
// Don't call directly to avoid exposing the built-in global object.
- var receiver =
- %_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
+ var receiver = %GetDefaultReceiver(replace);
replacement =
%_CallFunction(receiver, s, index, subject, replace);
} else {
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Aug 19 02:54:08
2011
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Aug 26 06:53:00
2011
@@ -3516,39 +3516,6 @@
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
context()->Plug(rax);
}
-
-
-void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>*
args) {
- ASSERT(args->length() == 1);
-
- // Load the function into rax.
- VisitForAccumulatorValue(args->at(0));
-
- // Prepare for the test.
- Label materialize_true, materialize_false;
- Label* if_true = NULL;
- Label* if_false = NULL;
- Label* fall_through = NULL;
- context()->PrepareTest(&materialize_true, &materialize_false,
- &if_true, &if_false, &fall_through);
-
- // Test for strict mode function.
- __ movq(rdx, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
- __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
- Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
- __ j(not_equal, if_true);
-
- // Test for native function.
- __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
- Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
- __ j(not_equal, if_true);
-
- // Not native or strict-mode function.
- __ jmp(if_false);
-
- PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- context()->Plug(if_true, if_false);
-}
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Fri Aug 26 01:45:47 2011
+++ /branches/bleeding_edge/test/cctest/test-api.cc Fri Aug 26 06:53:00 2011
@@ -15046,3 +15046,107 @@
context.Dispose();
}
+
+
+static void TestReceiver(Local<Value> expected_result,
+ Local<Value> expected_receiver,
+ const char* code) {
+ Local<Value> result = CompileRun(code);
+ CHECK(result->IsObject());
+ CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
+ CHECK(expected_result->Equals(result->ToObject()->Get(0)));
+}
+
+
+THREADED_TEST(ForeignFunctionReceiver) {
+ HandleScope scope;
+
+ // Create two contexts with different "id" properties ('i' and 'o').
+ // Call a function both from its own context and from a the foreign
+ // context, and see what "this" is bound to (returning both "this"
+ // and "this.id" for comparison).
+
+ Persistent<Context> foreign_context = v8::Context::New();
+ foreign_context->Enter();
+ Local<Value> foreign_function =
+ CompileRun("function func() { return { 0: this.id, "
+ " 1: this, "
+ " toString: function() { "
+ " return this[0];"
+ " }"
+ " };"
+ "}"
+ "var id = 'i';"
+ "func;");
+ CHECK(foreign_function->IsFunction());
+ foreign_context->Exit();
+
+ LocalContext context;
+
+ Local<String> password = v8_str("Password");
+ // Don't get hit by security checks when accessing foreign_context's
+ // global receiver (aka. global proxy).
+ context->SetSecurityToken(password);
+ foreign_context->SetSecurityToken(password);
+
+ Local<String> i = v8_str("i");
+ Local<String> o = v8_str("o");
+ Local<String> id = v8_str("id");
+
+ CompileRun("function ownfunc() { return { 0: this.id, "
+ " 1: this, "
+ " toString: function() { "
+ " return this[0];"
+ " }"
+ " };"
+ "}"
+ "var id = 'o';"
+ "ownfunc");
+ context->Global()->Set(v8_str("func"), foreign_function);
+
+ // Sanity check the contexts.
+ CHECK(i->Equals(foreign_context->Global()->Get(id)));
+ CHECK(o->Equals(context->Global()->Get(id)));
+
+ // Checking local function's receiver.
+ // Calling function using its call/apply methods.
+ TestReceiver(o, context->Global(), "ownfunc.call()");
+ TestReceiver(o, context->Global(), "ownfunc.apply()");
+ // Making calls through built-in functions.
+ TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
+ CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
+ CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
+ CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
+ // Calling with environment record as base.
+ TestReceiver(o, context->Global(), "ownfunc()");
+ // Calling with no base.
+ TestReceiver(o, context->Global(), "(1,ownfunc)()");
+
+ // Checking foreign function return value.
+ // Calling function using its call/apply methods.
+ TestReceiver(i, foreign_context->Global(), "func.call()");
+ TestReceiver(i, foreign_context->Global(), "func.apply()");
+ // Calling function using another context's call/apply methods.
+ TestReceiver(i, foreign_context->Global(),
+ "Function.prototype.call.call(func)");
+ TestReceiver(i, foreign_context->Global(),
+ "Function.prototype.call.apply(func)");
+ TestReceiver(i, foreign_context->Global(),
+ "Function.prototype.apply.call(func)");
+ TestReceiver(i, foreign_context->Global(),
+ "Function.prototype.apply.apply(func)");
+ // Making calls through built-in functions.
+ TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
+ // ToString(func()) is func()[0], i.e., the returned this.id.
+ CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
+ 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()");
+ // Calling with no base.
+ TestReceiver(o, context->Global(), "(1,func)()");
+
+ foreign_context.Dispose();
+}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev