Commit 0d8c343c authored by ager@chromium.org's avatar ager@chromium.org

Do not pass the global object as the receiver to strict-mode and

builtin replace and sort functions.

R=ricow@chromium.org
BUG=v8:1360
TEST=mjsunit/regress/regress-1360.js

Review URL: http://codereview.chromium.org/7283006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8488 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 89c83051
...@@ -3574,6 +3574,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { ...@@ -3574,6 +3574,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
} }
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) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') { if (name->length() > 0 && name->Get(0) == '_') {
......
...@@ -742,14 +742,15 @@ function ArraySort(comparefn) { ...@@ -742,14 +742,15 @@ function ArraySort(comparefn) {
else return x < y ? -1 : 1; else return x < y ? -1 : 1;
}; };
} }
var global_receiver = %GetGlobalReceiver(); var receiver =
%_IsNativeOrStrictMode(comparefn) ? void 0 : %GetGlobalReceiver();
function InsertionSort(a, from, to) { function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) { for (var i = from + 1; i < to; i++) {
var element = a[i]; var element = a[i];
for (var j = i - 1; j >= from; j--) { for (var j = i - 1; j >= from; j--) {
var tmp = a[j]; var tmp = a[j];
var order = %_CallFunction(global_receiver, tmp, element, comparefn); var order = %_CallFunction(receiver, tmp, element, comparefn);
if (order > 0) { if (order > 0) {
a[j + 1] = tmp; a[j + 1] = tmp;
} else { } else {
...@@ -771,14 +772,14 @@ function ArraySort(comparefn) { ...@@ -771,14 +772,14 @@ function ArraySort(comparefn) {
var v1 = a[to - 1]; var v1 = a[to - 1];
var middle_index = from + ((to - from) >> 1); var middle_index = from + ((to - from) >> 1);
var v2 = a[middle_index]; var v2 = a[middle_index];
var c01 = %_CallFunction(global_receiver, v0, v1, comparefn); var c01 = %_CallFunction(receiver, v0, v1, comparefn);
if (c01 > 0) { if (c01 > 0) {
// v1 < v0, so swap them. // v1 < v0, so swap them.
var tmp = v0; var tmp = v0;
v0 = v1; v0 = v1;
v1 = tmp; v1 = tmp;
} // v0 <= v1. } // v0 <= v1.
var c02 = %_CallFunction(global_receiver, v0, v2, comparefn); var c02 = %_CallFunction(receiver, v0, v2, comparefn);
if (c02 >= 0) { if (c02 >= 0) {
// v2 <= v0 <= v1. // v2 <= v0 <= v1.
var tmp = v0; var tmp = v0;
...@@ -787,7 +788,7 @@ function ArraySort(comparefn) { ...@@ -787,7 +788,7 @@ function ArraySort(comparefn) {
v1 = tmp; v1 = tmp;
} else { } else {
// v0 <= v1 && v0 < v2 // v0 <= v1 && v0 < v2
var c12 = %_CallFunction(global_receiver, v1, v2, comparefn); var c12 = %_CallFunction(receiver, v1, v2, comparefn);
if (c12 > 0) { if (c12 > 0) {
// v0 <= v2 < v1 // v0 <= v2 < v1
var tmp = v1; var tmp = v1;
...@@ -808,7 +809,7 @@ function ArraySort(comparefn) { ...@@ -808,7 +809,7 @@ function ArraySort(comparefn) {
// From i to high_start are elements that haven't been compared yet. // From i to high_start are elements that haven't been compared yet.
partition: for (var i = low_end + 1; i < high_start; i++) { partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i]; var element = a[i];
var order = %_CallFunction(global_receiver, element, pivot, comparefn); var order = %_CallFunction(receiver, element, pivot, comparefn);
if (order < 0) { if (order < 0) {
%_SwapElements(a, i, low_end); %_SwapElements(a, i, low_end);
low_end++; low_end++;
...@@ -817,7 +818,7 @@ function ArraySort(comparefn) { ...@@ -817,7 +818,7 @@ function ArraySort(comparefn) {
high_start--; high_start--;
if (high_start == i) break partition; if (high_start == i) break partition;
var top_elem = a[high_start]; var top_elem = a[high_start];
order = %_CallFunction(global_receiver, top_elem, pivot, comparefn); order = %_CallFunction(receiver, top_elem, pivot, comparefn);
} while (order > 0); } while (order > 0);
%_SwapElements(a, i, high_start); %_SwapElements(a, i, high_start);
if (order < 0) { if (order < 0) {
......
...@@ -6068,6 +6068,11 @@ void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { ...@@ -6068,6 +6068,11 @@ void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
} }
void HGraphBuilder::GenerateIsNativeOrStrictMode(CallRuntime* call) {
return Bailout("inlined runtime function: IsNativeOrStrictMode");
}
#undef CHECK_BAILOUT #undef CHECK_BAILOUT
#undef CHECK_ALIVE #undef CHECK_ALIVE
......
...@@ -3532,6 +3532,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { ...@@ -3532,6 +3532,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
} }
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) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') { if (name->length() > 0 && name->Get(0) == '_') {
......
...@@ -470,7 +470,8 @@ namespace internal { ...@@ -470,7 +470,8 @@ namespace internal {
F(IsRegExpEquivalent, 2, 1) \ F(IsRegExpEquivalent, 2, 1) \
F(HasCachedArrayIndex, 1, 1) \ F(HasCachedArrayIndex, 1, 1) \
F(GetCachedArrayIndex, 1, 1) \ F(GetCachedArrayIndex, 1, 1) \
F(FastAsciiArrayJoin, 2, 1) F(FastAsciiArrayJoin, 2, 1) \
F(IsNativeOrStrictMode, 1, 1)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
...@@ -251,7 +251,9 @@ function StringReplace(search, replace) { ...@@ -251,7 +251,9 @@ function StringReplace(search, replace) {
// Compute the string to replace with. // Compute the string to replace with.
if (IS_FUNCTION(replace)) { if (IS_FUNCTION(replace)) {
builder.add(%_CallFunction(%GetGlobalReceiver(), var receiver =
%_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
builder.add(%_CallFunction(receiver,
search, search,
start, start,
subject, subject,
...@@ -418,7 +420,8 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { ...@@ -418,7 +420,8 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) { if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
var match_start = 0; var match_start = 0;
var override = new InternalArray(null, 0, subject); var override = new InternalArray(null, 0, subject);
var receiver = %GetGlobalReceiver(); var receiver =
%_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
while (i < len) { while (i < len) {
var elem = res[i]; var elem = res[i];
if (%_IsSmi(elem)) { if (%_IsSmi(elem)) {
...@@ -475,8 +478,10 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { ...@@ -475,8 +478,10 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
// No captures, only the match, which is always valid. // No captures, only the match, which is always valid.
var s = SubString(subject, index, endOfMatch); var s = SubString(subject, index, endOfMatch);
// Don't call directly to avoid exposing the built-in global object. // Don't call directly to avoid exposing the built-in global object.
var receiver =
%_IsNativeOrStrictMode(replace) ? void 0 : %GetGlobalReceiver();
replacement = replacement =
%_CallFunction(%GetGlobalReceiver(), s, index, subject, replace); %_CallFunction(receiver, s, index, subject, replace);
} else { } else {
var parameters = new InternalArray(m + 2); var parameters = new InternalArray(m + 2);
for (var j = 0; j < m; j++) { for (var j = 0; j < m; j++) {
......
...@@ -3512,6 +3512,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { ...@@ -3512,6 +3512,39 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
} }
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) { void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name(); Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') { if (name->length() > 0 && name->Get(0) == '_') {
......
// Copyright 2011 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.
// Check the receiver for the sort and replace functions to
// Array.prototype.sort and String.prototype.replace.
var global = this;
function strict() { "use strict"; assertEquals(void 0, this); }
function non_strict() { assertEquals(global, this); }
[1,2,3].sort(strict);
[1,2,3].sort(non_strict);
"axc".replace("x", strict);
"axc".replace("x", non_strict);
...@@ -34,11 +34,6 @@ def FAIL_OK = FAIL, OKAY ...@@ -34,11 +34,6 @@ def FAIL_OK = FAIL, OKAY
S15.3.4.5_A1: FAIL S15.3.4.5_A1: FAIL
S15.3.4.5_A2: FAIL S15.3.4.5_A2: FAIL
# String replace and array sort leaks the global object to strict mode
# callbacks.
S15.5.4.11_A12: FAIL
S15.4.4.11_A8: FAIL
# '__proto__' should be treated as a normal property in JSON. # '__proto__' should be treated as a normal property in JSON.
S15.12.2_A1: FAIL S15.12.2_A1: FAIL
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment