Revision: 7474
Author: [email protected]
Date: Fri Apr 1 04:54:04 2011
Log: Increase coverage of global loads in optimized code
In the cases where a global property cell cannot be used in the optimized
code
use standard load ic to get the property instead of bailing out.
This is re-committing r7212 and r7215 which where reverted in r7239 with
the addition of recoring the source position in the hydrogen code for the
LoadGlobalCell instruction. To record that position an optional position
field has been added to the variable proxy AST node.
Review URL: http://codereview.chromium.org/6758007
http://code.google.com/p/v8/source/detail?r=7474
Added:
/branches/bleeding_edge/test/mjsunit/compiler/global-accessors.js
Modified:
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.h
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/checks.h
/branches/bleeding_edge/src/hydrogen-instructions.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.h
/branches/bleeding_edge/src/parser.cc
/branches/bleeding_edge/src/scopes.cc
/branches/bleeding_edge/src/scopes.h
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.h
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/compiler/global-accessors.js Fri
Apr 1 04:54:04 2011
@@ -0,0 +1,47 @@
+// Copyright 2010 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.
+
+// This test tests that no bailouts are missing by not hitting asserts in
debug
+// mode.
+
+test_count_operation()
+test_compound_assignment()
+
+function f() {}
+function test_count_operation()
+{
+ this.__defineSetter__('x', f);
+ this.__defineGetter__('x', f);
+ x = x++;
+}
+
+function test_compound_assignment()
+{
+ this.__defineSetter__('y', f);
+ this.__defineGetter__('y', f);
+ y += y;
+}
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Apr 1 03:52:18
2011
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Apr 1 04:54:04
2011
@@ -1622,26 +1622,25 @@
break;
}
+ // For compound assignments we need another deoptimization point after
the
+ // variable/property load.
if (expr->is_compound()) {
{ AccumulatorValueContext context(this);
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var());
+ PrepareForBailout(expr->target(), TOS_REG);
break;
case NAMED_PROPERTY:
EmitNamedPropertyLoad(property);
+ PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
break;
case KEYED_PROPERTY:
EmitKeyedPropertyLoad(property);
+ PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
break;
}
}
-
- // For property compound assignments we need another deoptimization
- // point after the property load.
- if (property != NULL) {
- PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
- }
Token::Value op = expr->binary_op();
__ push(r0); // Left operand goes on the stack.
@@ -3883,7 +3882,11 @@
// We need a second deoptimization point after loading the value
// in case evaluating the property load my have a side effect.
- PrepareForBailout(expr->increment(), TOS_REG);
+ if (assign_type == VARIABLE) {
+ PrepareForBailout(expr->expression(), TOS_REG);
+ } else {
+ PrepareForBailout(expr->increment(), TOS_REG);
+ }
// Call ToNumber only if operand is not a smi.
Label no_conversion;
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Fri Mar 25 04:16:29 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Fri Apr 1 04:54:04 2011
@@ -1723,12 +1723,19 @@
}
-LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
- LLoadGlobal* result = new LLoadGlobal();
+LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
+ LLoadGlobalCell* result = new LLoadGlobalCell;
return instr->check_hole_value()
? AssignEnvironment(DefineAsRegister(result))
: DefineAsRegister(result);
}
+
+
+LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric*
instr) {
+ LOperand* global_object = UseFixed(instr->global_object(), r0);
+ LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object);
+ return MarkAsCall(DefineFixed(result, r0), instr);
+}
LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h Thu Mar 24 15:14:15 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.h Fri Apr 1 04:54:04 2011
@@ -119,7 +119,8 @@
V(LoadElements) \
V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
- V(LoadGlobal) \
+ V(LoadGlobalCell) \
+ V(LoadGlobalGeneric) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
@@ -1259,10 +1260,25 @@
};
-class LLoadGlobal: public LTemplateInstruction<1, 0, 0> {
+class LLoadGlobalCell: public LTemplateInstruction<1, 0, 0> {
public:
- DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load-global")
- DECLARE_HYDROGEN_ACCESSOR(LoadGlobal)
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell, "load-global-cell")
+ DECLARE_HYDROGEN_ACCESSOR(LoadGlobalCell)
+};
+
+
+class LLoadGlobalGeneric: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadGlobalGeneric(LOperand* global_object) {
+ inputs_[0] = global_object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
+
+ LOperand* global_object() { return inputs_[0]; }
+ Handle<Object> name() const { return hydrogen()->name(); }
+ bool for_typeof() const { return hydrogen()->for_typeof(); }
};
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Mar 25
03:29:34 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Apr 1
04:54:04 2011
@@ -2163,7 +2163,7 @@
}
-void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
+void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
Register result = ToRegister(instr->result());
__ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell())));
__ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
@@ -2173,6 +2173,18 @@
DeoptimizeIf(eq, instr->environment());
}
}
+
+
+void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
+ ASSERT(ToRegister(instr->global_object()).is(r0));
+ ASSERT(ToRegister(instr->result()).is(r0));
+
+ __ mov(r2, Operand(instr->name()));
+ RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET
+ :
RelocInfo::CODE_TARGET_CONTEXT;
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, mode, instr);
+}
void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
=======================================
--- /branches/bleeding_edge/src/ast.cc Wed Mar 23 06:40:07 2011
+++ /branches/bleeding_edge/src/ast.cc Fri Apr 1 04:54:04 2011
@@ -77,20 +77,23 @@
var_(NULL), // Will be set by the call to BindTo.
is_this_(var->is_this()),
inside_with_(false),
- is_trivial_(false) {
+ is_trivial_(false),
+ position_(RelocInfo::kNoPosition) {
BindTo(var);
}
VariableProxy::VariableProxy(Handle<String> name,
bool is_this,
- bool inside_with)
+ bool inside_with,
+ int position)
: name_(name),
var_(NULL),
is_this_(is_this),
inside_with_(inside_with),
- is_trivial_(false) {
- // names must be canonicalized for fast equality checks
+ is_trivial_(false),
+ position_(position) {
+ // Names must be canonicalized for fast equality checks.
ASSERT(name->IsSymbol());
}
@@ -622,24 +625,21 @@
bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
- Handle<String> name) {
+ LookupResult* lookup) {
target_ = Handle<JSFunction>::null();
cell_ = Handle<JSGlobalPropertyCell>::null();
- LookupResult lookup;
- global->Lookup(*name, &lookup);
- if (lookup.IsProperty() &&
- lookup.type() == NORMAL &&
- lookup.holder() == *global) {
- cell_ = Handle<JSGlobalPropertyCell>(global->GetPropertyCell(&lookup));
- if (cell_->value()->IsJSFunction()) {
- Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
- // If the function is in new space we assume it's more likely to
- // change and thus prefer the general IC code.
- if (!HEAP->InNewSpace(*candidate) &&
- CanCallWithoutIC(candidate, arguments()->length())) {
- target_ = candidate;
- return true;
- }
+ ASSERT(lookup->IsProperty() &&
+ lookup->type() == NORMAL &&
+ lookup->holder() == *global);
+ cell_ = Handle<JSGlobalPropertyCell>(global->GetPropertyCell(lookup));
+ if (cell_->value()->IsJSFunction()) {
+ Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
+ // If the function is in new space we assume it's more likely to
+ // change and thus prefer the general IC code.
+ if (!HEAP->InNewSpace(*candidate) &&
+ CanCallWithoutIC(candidate, arguments()->length())) {
+ target_ = candidate;
+ return true;
}
}
return false;
=======================================
--- /branches/bleeding_edge/src/ast.h Fri Apr 1 03:52:18 2011
+++ /branches/bleeding_edge/src/ast.h Fri Apr 1 04:54:04 2011
@@ -1135,6 +1135,7 @@
Variable* var() const { return var_; }
bool is_this() const { return is_this_; }
bool inside_with() const { return inside_with_; }
+ int position() const { return position_; }
void MarkAsTrivial() { is_trivial_ = true; }
@@ -1147,8 +1148,12 @@
bool is_this_;
bool inside_with_;
bool is_trivial_;
-
- VariableProxy(Handle<String> name, bool is_this, bool inside_with);
+ int position_;
+
+ VariableProxy(Handle<String> name,
+ bool is_this,
+ bool inside_with,
+ int position = RelocInfo::kNoPosition);
explicit VariableProxy(bool is_this);
friend class Scope;
@@ -1316,7 +1321,7 @@
Handle<JSGlobalPropertyCell> cell() { return cell_; }
bool ComputeTarget(Handle<Map> type, Handle<String> name);
- bool ComputeGlobalTarget(Handle<GlobalObject> global, Handle<String>
name);
+ bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupResult*
lookup);
// Bailout support.
int ReturnId() const { return return_id_; }
=======================================
--- /branches/bleeding_edge/src/checks.h Wed Dec 15 00:07:27 2010
+++ /branches/bleeding_edge/src/checks.h Fri Apr 1 04:54:04 2011
@@ -271,6 +271,8 @@
#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2)
#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2)
#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2)
+#define ASSERT_LT(v1, v2) CHECK_LT(v1, v2)
+#define ASSERT_LE(v1, v2) CHECK_LE(v1, v2)
#define SLOW_ASSERT(condition) if (EnableSlowAsserts()) CHECK(condition)
#else
#define ASSERT_RESULT(expr) (expr)
@@ -278,6 +280,8 @@
#define ASSERT_EQ(v1, v2) ((void) 0)
#define ASSERT_NE(v1, v2) ((void) 0)
#define ASSERT_GE(v1, v2) ((void) 0)
+#define ASSERT_LT(v1, v2) ((void) 0)
+#define ASSERT_LE(v1, v2) ((void) 0)
#define SLOW_ASSERT(condition) ((void) 0)
#endif
// Static asserts has no impact on runtime performance, so they can be
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Mar 28
06:05:36 2011
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Fri Apr 1
04:54:04 2011
@@ -1342,10 +1342,15 @@
}
-void HLoadGlobal::PrintDataTo(StringStream* stream) {
+void HLoadGlobalCell::PrintDataTo(StringStream* stream) {
stream->Add("[%p]", *cell());
if (check_hole_value()) stream->Add(" (deleteable/read-only)");
}
+
+
+void HLoadGlobalGeneric::PrintDataTo(StringStream* stream) {
+ stream->Add("%o ", *name());
+}
void HStoreGlobal::PrintDataTo(StringStream* stream) {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Thu Mar 24 15:14:15
2011
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Fri Apr 1 04:54:04
2011
@@ -124,7 +124,8 @@
V(LoadElements) \
V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
- V(LoadGlobal) \
+ V(LoadGlobalCell) \
+ V(LoadGlobalGeneric) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
@@ -2809,9 +2810,9 @@
};
-class HLoadGlobal: public HTemplateInstruction<0> {
+class HLoadGlobalCell: public HTemplateInstruction<0> {
public:
- HLoadGlobal(Handle<JSGlobalPropertyCell> cell, bool check_hole_value)
+ HLoadGlobalCell(Handle<JSGlobalPropertyCell> cell, bool check_hole_value)
: cell_(cell), check_hole_value_(check_hole_value) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
@@ -2832,11 +2833,11 @@
return Representation::None();
}
- DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load_global")
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell, "load_global_cell")
protected:
virtual bool DataEquals(HValue* other) {
- HLoadGlobal* b = HLoadGlobal::cast(other);
+ HLoadGlobalCell* b = HLoadGlobalCell::cast(other);
return cell_.is_identical_to(b->cell());
}
@@ -2846,6 +2847,38 @@
};
+class HLoadGlobalGeneric: public HBinaryOperation {
+ public:
+ HLoadGlobalGeneric(HValue* context,
+ HValue* global_object,
+ Handle<Object> name,
+ bool for_typeof)
+ : HBinaryOperation(context, global_object),
+ name_(name),
+ for_typeof_(for_typeof) {
+ set_representation(Representation::Tagged());
+ SetAllSideEffects();
+ }
+
+ HValue* context() { return OperandAt(0); }
+ HValue* global_object() { return OperandAt(1); }
+ Handle<Object> name() const { return name_; }
+ bool for_typeof() const { return for_typeof_; }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load_global_generic")
+
+ private:
+ Handle<Object> name_;
+ bool for_typeof_;
+};
+
+
class HStoreGlobal: public HUnaryOperation {
public:
HStoreGlobal(HValue* value,
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Apr 1 04:41:36 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Fri Apr 1 04:54:04 2011
@@ -1980,7 +1980,10 @@
// Implementation of utility classes to represent an expression's context
in
// the AST.
AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
- : owner_(owner), kind_(kind), outer_(owner->ast_context()) {
+ : owner_(owner),
+ kind_(kind),
+ outer_(owner->ast_context()),
+ for_typeof_(false) {
owner->set_ast_context(this); // Push.
#ifdef DEBUG
original_length_ = owner->environment()->length();
@@ -2124,6 +2127,14 @@
}
+void HGraphBuilder::VisitForTypeOf(Expression* expr) {
+ ValueContext for_value(this);
+ for_value.set_for_typeof(true);
+ Visit(expr);
+}
+
+
+
void HGraphBuilder::VisitForControl(Expression* expr,
HBasicBlock* true_block,
HBasicBlock* false_block) {
@@ -2833,29 +2844,21 @@
}
-void HGraphBuilder::LookupGlobalPropertyCell(Variable* var,
- LookupResult* lookup,
- bool is_store) {
- if (var->is_this()) {
- BAILOUT("global this reference");
- }
- if (!info()->has_global_object()) {
- BAILOUT("no global object to optimize VariableProxy");
+HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty(
+ Variable* var, LookupResult* lookup, bool is_store) {
+ if (var->is_this() || !info()->has_global_object()) {
+ return kUseGeneric;
}
Handle<GlobalObject> global(info()->global_object());
global->Lookup(*var->name(), lookup);
- if (!lookup->IsProperty()) {
- BAILOUT("global variable cell not yet introduced");
- }
- if (lookup->type() != NORMAL) {
- BAILOUT("global variable has accessors");
- }
- if (is_store && lookup->IsReadOnly()) {
- BAILOUT("read-only global variable");
- }
- if (lookup->holder() != *global) {
- BAILOUT("global property on prototype of global object");
- }
+ if (!lookup->IsProperty() ||
+ lookup->type() != NORMAL ||
+ (is_store && lookup->IsReadOnly()) ||
+ lookup->holder() != *global) {
+ return kUseGeneric;
+ }
+
+ return kUseCell;
}
@@ -2891,19 +2894,33 @@
ast_context()->ReturnInstruction(instr, expr->id());
} else if (variable->is_global()) {
LookupResult lookup;
- LookupGlobalPropertyCell(variable, &lookup, false);
- CHECK_BAILOUT;
-
- Handle<GlobalObject> global(info()->global_object());
- // TODO(3039103): Handle global property load through an IC call when
access
- // checks are enabled.
- if (global->IsAccessCheckNeeded()) {
- BAILOUT("global object requires access check");
- }
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
- bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
- HLoadGlobal* instr = new HLoadGlobal(cell, check_hole);
- ast_context()->ReturnInstruction(instr, expr->id());
+ GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup,
false);
+
+ if (type == kUseCell &&
+ info()->global_object()->IsAccessCheckNeeded()) {
+ type = kUseGeneric;
+ }
+
+ if (type == kUseCell) {
+ Handle<GlobalObject> global(info()->global_object());
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
+ bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
+ HLoadGlobalCell* instr = new HLoadGlobalCell(cell, check_hole);
+ ast_context()->ReturnInstruction(instr, expr->id());
+ } else {
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HGlobalObject* global_object = new HGlobalObject(context);
+ AddInstruction(global_object);
+ HLoadGlobalGeneric* instr =
+ new HLoadGlobalGeneric(context,
+ global_object,
+ variable->name(),
+ ast_context()->is_for_typeof());
+ instr->set_position(expr->position());
+ ASSERT(instr->HasSideEffects());
+ ast_context()->ReturnInstruction(instr, expr->id());
+ }
} else {
BAILOUT("reference to a variable which requires dynamic lookup");
}
@@ -3274,16 +3291,18 @@
int position,
int ast_id) {
LookupResult lookup;
- LookupGlobalPropertyCell(var, &lookup, true);
- CHECK_BAILOUT;
-
- bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
- Handle<GlobalObject> global(info()->global_object());
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
- HInstruction* instr = new HStoreGlobal(value, cell, check_hole);
- instr->set_position(position);
- AddInstruction(instr);
- if (instr->HasSideEffects()) AddSimulate(ast_id);
+ GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
+ if (type == kUseCell) {
+ bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
+ Handle<GlobalObject> global(info()->global_object());
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
+ HInstruction* instr = new HStoreGlobal(value, cell, check_hole);
+ instr->set_position(position);
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(ast_id);
+ } else {
+ BAILOUT("global store only supported for cells");
+ }
}
@@ -4317,10 +4336,12 @@
// If there is a global property cell for the name at compile time
and
// access check is not enabled we assume that the function will not
change
// and generate optimized code for calling the function.
- if (info()->has_global_object() &&
+ LookupResult lookup;
+ GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup,
false);
+ if (type == kUseCell &&
!info()->global_object()->IsAccessCheckNeeded()) {
Handle<GlobalObject> global(info()->global_object());
- known_global_function = expr->ComputeGlobalTarget(global,
var->name());
+ known_global_function = expr->ComputeGlobalTarget(global, &lookup);
}
if (known_global_function) {
// Push the global object instead of the global receiver because
@@ -4523,7 +4544,8 @@
}
} else if (op == Token::TYPEOF) {
- VISIT_FOR_VALUE(expr->expression());
+ VisitForTypeOf(expr->expression());
+ if (HasStackOverflow()) return;
HValue* value = Pop();
ast_context()->ReturnInstruction(new HTypeof(value), expr->id());
@@ -4926,7 +4948,8 @@
if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) &&
left_unary != NULL && left_unary->op() == Token::TYPEOF &&
right_literal != NULL && right_literal->handle()->IsString()) {
- VISIT_FOR_VALUE(left_unary->expression());
+ VisitForTypeOf(left_unary->expression());
+ if (HasStackOverflow()) return;
HValue* left = Pop();
HInstruction* instr = new HTypeofIs(left,
Handle<String>::cast(right_literal->handle()));
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Fri Apr 1 04:41:36 2011
+++ /branches/bleeding_edge/src/hydrogen.h Fri Apr 1 04:54:04 2011
@@ -452,6 +452,9 @@
// environment simulation if necessary) and then fill this context with
// the instruction as value.
virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
+
+ void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
+ bool is_for_typeof() { return for_typeof_; }
protected:
AstContext(HGraphBuilder* owner, Expression::Context kind);
@@ -469,6 +472,7 @@
HGraphBuilder* owner_;
Expression::Context kind_;
AstContext* outer_;
+ bool for_typeof_;
};
@@ -737,6 +741,7 @@
void Bind(Variable* var, HValue* value) { environment()->Bind(var,
value); }
void VisitForValue(Expression* expr);
+ void VisitForTypeOf(Expression* expr);
void VisitForEffect(Expression* expr);
void VisitForControl(Expression* expr,
HBasicBlock* true_block,
@@ -772,9 +777,13 @@
HBasicBlock* CreateLoopHeaderBlock();
// Helpers for flow graph construction.
- void LookupGlobalPropertyCell(Variable* var,
- LookupResult* lookup,
- bool is_store);
+ enum GlobalPropertyAccess {
+ kUseCell,
+ kUseGeneric
+ };
+ GlobalPropertyAccess LookupGlobalProperty(Variable* var,
+ LookupResult* lookup,
+ bool is_store);
bool TryArgumentsAccess(Property* expr);
bool TryCallApply(Call* expr);
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Apr 1
03:52:18 2011
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Apr 1
04:54:04 2011
@@ -1563,26 +1563,25 @@
}
}
+ // For compound assignments we need another deoptimization point after
the
+ // variable/property load.
if (expr->is_compound()) {
{ AccumulatorValueContext context(this);
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var());
+ PrepareForBailout(expr->target(), TOS_REG);
break;
case NAMED_PROPERTY:
EmitNamedPropertyLoad(property);
+ PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
break;
case KEYED_PROPERTY:
EmitKeyedPropertyLoad(property);
+ PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
break;
}
}
-
- // For property compound assignments we need another deoptimization
- // point after the property load.
- if (property != NULL) {
- PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
- }
Token::Value op = expr->binary_op();
__ push(eax); // Left operand goes on the stack.
@@ -3833,7 +3832,11 @@
// We need a second deoptimization point after loading the value
// in case evaluating the property load my have a side effect.
- PrepareForBailout(expr->increment(), TOS_REG);
+ if (assign_type == VARIABLE) {
+ PrepareForBailout(expr->expression(), TOS_REG);
+ } else {
+ PrepareForBailout(expr->increment(), TOS_REG);
+ }
// Call ToNumber only if operand is not a smi.
NearLabel no_conversion;
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Apr 1
01:03:34 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Apr 1
04:54:04 2011
@@ -2032,7 +2032,7 @@
}
-void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
+void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
Register result = ToRegister(instr->result());
__ mov(result, Operand::Cell(instr->hydrogen()->cell()));
if (instr->hydrogen()->check_hole_value()) {
@@ -2040,6 +2040,19 @@
DeoptimizeIf(equal, instr->environment());
}
}
+
+
+void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
+ ASSERT(ToRegister(instr->global_object()).is(eax));
+ ASSERT(ToRegister(instr->result()).is(eax));
+
+ __ mov(ecx, instr->name());
+ RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
+
RelocInfo::CODE_TARGET_CONTEXT;
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, mode, instr);
+}
void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Mar 31 09:17:37
2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri Apr 1 04:54:04
2011
@@ -1187,7 +1187,7 @@
LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
++argument_count_;
- LOperand* argument = UseOrConstant(instr->argument());
+ LOperand* argument = UseAny(instr->argument());
return new LPushArgument(argument);
}
@@ -1745,12 +1745,20 @@
}
-LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
- LLoadGlobal* result = new LLoadGlobal;
+LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
+ LLoadGlobalCell* result = new LLoadGlobalCell;
return instr->check_hole_value()
? AssignEnvironment(DefineAsRegister(result))
: DefineAsRegister(result);
}
+
+
+LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric*
instr) {
+ LOperand* context = UseFixed(instr->context(), esi);
+ LOperand* global_object = UseFixed(instr->global_object(), eax);
+ LLoadGlobalGeneric* result = new LLoadGlobalGeneric(context,
global_object);
+ return MarkAsCall(DefineFixed(result, eax), instr);
+}
LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h Thu Mar 24 15:14:15 2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h Fri Apr 1 04:54:04 2011
@@ -121,7 +121,8 @@
V(LoadElements) \
V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
- V(LoadGlobal) \
+ V(LoadGlobalCell) \
+ V(LoadGlobalGeneric) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
@@ -1292,10 +1293,27 @@
};
-class LLoadGlobal: public LTemplateInstruction<1, 0, 0> {
+class LLoadGlobalCell: public LTemplateInstruction<1, 0, 0> {
public:
- DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load-global")
- DECLARE_HYDROGEN_ACCESSOR(LoadGlobal)
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell, "load-global-cell")
+ DECLARE_HYDROGEN_ACCESSOR(LoadGlobalCell)
+};
+
+
+class LLoadGlobalGeneric: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LLoadGlobalGeneric(LOperand* context, LOperand* global_object) {
+ inputs_[0] = context;
+ inputs_[1] = global_object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* global_object() { return inputs_[1]; }
+ Handle<Object> name() const { return hydrogen()->name(); }
+ bool for_typeof() const { return hydrogen()->for_typeof(); }
};
=======================================
--- /branches/bleeding_edge/src/parser.cc Tue Mar 29 06:06:48 2011
+++ /branches/bleeding_edge/src/parser.cc Fri Apr 1 04:54:04 2011
@@ -2883,7 +2883,9 @@
case Token::FUTURE_RESERVED_WORD: {
Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
- result = top_scope_->NewUnresolved(name, inside_with());
+ result = top_scope_->NewUnresolved(name,
+ inside_with(),
+ scanner().location().beg_pos);
break;
}
=======================================
--- /branches/bleeding_edge/src/scopes.cc Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/scopes.cc Fri Apr 1 04:54:04 2011
@@ -361,12 +361,14 @@
}
-VariableProxy* Scope::NewUnresolved(Handle<String> name, bool inside_with)
{
+VariableProxy* Scope::NewUnresolved(Handle<String> name,
+ bool inside_with,
+ int position) {
// Note that we must not share the unresolved variables with
// the same name because they may be removed selectively via
// RemoveUnresolved().
ASSERT(!resolved());
- VariableProxy* proxy = new VariableProxy(name, false, inside_with);
+ VariableProxy* proxy = new VariableProxy(name, false, inside_with,
position);
unresolved_.Add(proxy);
return proxy;
}
=======================================
--- /branches/bleeding_edge/src/scopes.h Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/scopes.h Fri Apr 1 04:54:04 2011
@@ -149,7 +149,9 @@
void AddParameter(Variable* var);
// Create a new unresolved variable.
- virtual VariableProxy* NewUnresolved(Handle<String> name, bool
inside_with);
+ virtual VariableProxy* NewUnresolved(Handle<String> name,
+ bool inside_with,
+ int position =
RelocInfo::kNoPosition);
// Remove a unresolved variable. During parsing, an unresolved variable
// may have been added optimistically, but then only the variable name
@@ -479,7 +481,9 @@
virtual Variable* Lookup(Handle<String> name) { return NULL; }
- virtual VariableProxy* NewUnresolved(Handle<String> name, bool
inside_with) {
+ virtual VariableProxy* NewUnresolved(Handle<String> name,
+ bool inside_with,
+ int position =
RelocInfo::kNoPosition) {
return NULL;
}
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Apr 1 03:52:18
2011
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Apr 1 04:54:04
2011
@@ -1576,26 +1576,25 @@
}
}
+ // For compound assignments we need another deoptimization point after
the
+ // variable/property load.
if (expr->is_compound()) {
{ AccumulatorValueContext context(this);
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var());
+ PrepareForBailout(expr->target(), TOS_REG);
break;
case NAMED_PROPERTY:
EmitNamedPropertyLoad(property);
+ PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
break;
case KEYED_PROPERTY:
EmitKeyedPropertyLoad(property);
+ PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
break;
}
}
-
- // For property compound assignments we need another deoptimization
- // point after the property load.
- if (property != NULL) {
- PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
- }
Token::Value op = expr->binary_op();
__ push(rax); // Left operand goes on the stack.
@@ -3809,7 +3808,11 @@
// We need a second deoptimization point after loading the value
// in case evaluating the property load my have a side effect.
- PrepareForBailout(expr->increment(), TOS_REG);
+ if (assign_type == VARIABLE) {
+ PrepareForBailout(expr->expression(), TOS_REG);
+ } else {
+ PrepareForBailout(expr->increment(), TOS_REG);
+ }
// Call ToNumber only if operand is not a smi.
NearLabel no_conversion;
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Mar 28
06:34:10 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Apr 1
04:54:04 2011
@@ -2019,7 +2019,7 @@
}
-void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
+void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
Register result = ToRegister(instr->result());
if (result.is(rax)) {
__ load_rax(instr->hydrogen()->cell().location(),
@@ -2033,6 +2033,18 @@
DeoptimizeIf(equal, instr->environment());
}
}
+
+
+void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
+ ASSERT(ToRegister(instr->global_object()).is(rax));
+ ASSERT(ToRegister(instr->result()).is(rax));
+
+ __ Move(rcx, instr->name());
+ RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
+
RelocInfo::CODE_TARGET_CONTEXT;
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, mode, instr);
+}
void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Thu Mar 31 09:17:37 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Fri Apr 1 04:54:04 2011
@@ -1717,12 +1717,19 @@
}
-LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
- LLoadGlobal* result = new LLoadGlobal;
+LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
+ LLoadGlobalCell* result = new LLoadGlobalCell;
return instr->check_hole_value()
? AssignEnvironment(DefineAsRegister(result))
: DefineAsRegister(result);
}
+
+
+LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric*
instr) {
+ LOperand* global_object = UseFixed(instr->global_object(), rax);
+ LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object);
+ return MarkAsCall(DefineFixed(result, rax), instr);
+}
LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h Thu Mar 24 15:14:15 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h Fri Apr 1 04:54:04 2011
@@ -118,7 +118,8 @@
V(LoadContextSlot) \
V(LoadElements) \
V(LoadExternalArrayPointer) \
- V(LoadGlobal) \
+ V(LoadGlobalCell) \
+ V(LoadGlobalGeneric) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
@@ -1245,10 +1246,25 @@
};
-class LLoadGlobal: public LTemplateInstruction<1, 0, 0> {
+class LLoadGlobalCell: public LTemplateInstruction<1, 0, 0> {
public:
- DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load-global")
- DECLARE_HYDROGEN_ACCESSOR(LoadGlobal)
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell, "load-global-cell")
+ DECLARE_HYDROGEN_ACCESSOR(LoadGlobalCell)
+};
+
+
+class LLoadGlobalGeneric: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadGlobalGeneric(LOperand* global_object) {
+ inputs_[0] = global_object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
+
+ LOperand* global_object() { return inputs_[0]; }
+ Handle<Object> name() const { return hydrogen()->name(); }
+ bool for_typeof() const { return hydrogen()->for_typeof(); }
};
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev