Index: src/mips/full-codegen-mips.cc |
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc |
index dca171359ff0897152e7dc3d9fb80da622538895..b3f0540872dbd0c32099d53f8796d6d535b46cc7 100644 |
--- a/src/mips/full-codegen-mips.cc |
+++ b/src/mips/full-codegen-mips.cc |
@@ -278,7 +278,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { |
// constant. |
if (scope()->is_function_scope() && scope()->function() != NULL) { |
int ignored = 0; |
- EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); |
+ EmitDeclaration(scope()->function(), CONST, NULL, &ignored); |
} |
VisitDeclarations(scope()->declarations()); |
} |
@@ -721,7 +721,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
- Variable::Mode mode, |
+ VariableMode mode, |
FunctionLiteral* function, |
int* global_count) { |
// If it was not possible to allocate the variable at compile time, we |
@@ -739,7 +739,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
Comment cmnt(masm_, "[ Declaration"); |
VisitForAccumulatorValue(function); |
__ sw(result_register(), StackOperand(variable)); |
- } else if (mode == Variable::CONST || mode == Variable::LET) { |
+ } else if (mode == CONST || mode == LET) { |
Comment cmnt(masm_, "[ Declaration"); |
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
__ sw(t0, StackOperand(variable)); |
@@ -775,7 +775,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
EMIT_REMEMBERED_SET, |
OMIT_SMI_CHECK); |
PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
- } else if (mode == Variable::CONST || mode == Variable::LET) { |
+ } else if (mode == CONST || mode == LET) { |
Comment cmnt(masm_, "[ Declaration"); |
__ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
__ sw(at, ContextOperand(cp, variable->index())); |
@@ -788,10 +788,8 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
Comment cmnt(masm_, "[ Declaration"); |
__ li(a2, Operand(variable->name())); |
// Declaration nodes are always introduced in one of three modes. |
- ASSERT(mode == Variable::VAR || |
- mode == Variable::CONST || |
- mode == Variable::LET); |
- PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; |
+ ASSERT(mode == VAR || mode == CONST || mode == LET); |
+ PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; |
__ li(a1, Operand(Smi::FromInt(attr))); |
// Push initial value, if any. |
// Note: For variables we must not push an initial value (such as |
@@ -801,7 +799,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
__ Push(cp, a2, a1); |
// Push initial value for function declaration. |
VisitForStackValue(function); |
- } else if (mode == Variable::CONST || mode == Variable::LET) { |
+ } else if (mode == CONST || mode == LET) { |
__ LoadRoot(a0, Heap::kTheHoleValueRootIndex); |
__ Push(cp, a2, a1, a0); |
} else { |
@@ -1223,17 +1221,25 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, |
// introducing variables. In those cases, we do not want to |
// perform a runtime call for all variables in the scope |
// containing the eval. |
- if (var->mode() == Variable::DYNAMIC_GLOBAL) { |
+ if (var->mode() == DYNAMIC_GLOBAL) { |
EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
__ Branch(done); |
- } else if (var->mode() == Variable::DYNAMIC_LOCAL) { |
+ } else if (var->mode() == DYNAMIC_LOCAL) { |
Variable* local = var->local_if_not_shadowed(); |
__ lw(v0, ContextSlotOperandCheckExtensions(local, slow)); |
- if (local->mode() == Variable::CONST) { |
+ if (local->mode() == CONST || |
+ local->mode() == LET) { |
__ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
__ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
- __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
- __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole. |
+ if (local->mode() == CONST) { |
+ __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
+ __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole. |
+ } else { // LET |
+ __ Branch(done, ne, at, Operand(zero_reg)); |
+ __ li(a0, Operand(var->name())); |
+ __ push(a0); |
+ __ CallRuntime(Runtime::kThrowReferenceError, 1); |
+ } |
} |
__ Branch(done); |
} |
@@ -1266,14 +1272,14 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
Comment cmnt(masm_, var->IsContextSlot() |
? "Context variable" |
: "Stack variable"); |
- if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { |
+ if (var->mode() != LET && var->mode() != CONST) { |
context()->Plug(var); |
} else { |
// Let and const need a read barrier. |
GetVar(v0, var); |
__ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
__ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
- if (var->mode() == Variable::LET) { |
+ if (var->mode() == LET) { |
Label done; |
__ Branch(&done, ne, at, Operand(zero_reg)); |
__ li(a0, Operand(var->name())); |
@@ -1513,15 +1519,23 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
VisitForAccumulatorValue(subexpr); |
// Store the subexpression value in the array's elements. |
- __ lw(a1, MemOperand(sp)); // Copy of array literal. |
- __ lw(a1, FieldMemOperand(a1, JSObject::kElementsOffset)); |
+ __ lw(t6, MemOperand(sp)); // Copy of array literal. |
+ __ lw(a1, FieldMemOperand(t6, JSObject::kElementsOffset)); |
int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
__ sw(result_register(), FieldMemOperand(a1, offset)); |
+ Label no_map_change; |
+ __ JumpIfSmi(result_register(), &no_map_change); |
// Update the write barrier for the array store with v0 as the scratch |
// register. |
__ RecordWriteField( |
- a1, offset, result_register(), a2, kRAHasBeenSaved, kDontSaveFPRegs); |
+ a1, offset, result_register(), a2, kRAHasBeenSaved, kDontSaveFPRegs, |
+ EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
+ __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset)); |
+ __ CheckFastSmiOnlyElements(a3, a2, &no_map_change); |
+ __ push(t6); // Copy of array literal. |
+ __ CallRuntime(Runtime::kNonSmiElementStored, 1); |
+ __ bind(&no_map_change); |
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
} |
@@ -1873,7 +1887,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
} |
- } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { |
+ } else if (var->mode() == LET && op != Token::INIT_LET) { |
// Non-initializing assignment to let variable needs a write barrier. |
if (var->IsLookupSlot()) { |
__ push(v0); // Value. |
@@ -1903,7 +1917,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
} |
} |
- } else if (var->mode() != Variable::CONST) { |
+ } else if (var->mode() != CONST) { |
// Assignment to var or initializing assignment to let. |
if (var->IsStackAllocated() || var->IsContextSlot()) { |
MemOperand location = VarOperand(var, a1); |
@@ -2194,7 +2208,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { |
// context lookup in the runtime system. |
Label done; |
Variable* var = proxy->var(); |
- if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { |
+ if (!var->IsUnallocated() && var->mode() == DYNAMIC_GLOBAL) { |
Label slow; |
EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); |
// Push the function and resolve eval. |
@@ -2695,18 +2709,23 @@ void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { |
// Check that the object is a JS object but take special care of JS |
// functions to make sure they have 'Function' as their class. |
+ // Assume that there are only two callable types, and one of them is at |
+ // either end of the type range for JS object types. Saves extra comparisons. |
+ STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
__ GetObjectType(v0, v0, a1); // Map is now in v0. |
__ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); |
- // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and |
- // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
- // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
- STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
- STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
- LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
- __ Branch(&function, ge, a1, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE)); |
+ STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
+ FIRST_SPEC_OBJECT_TYPE + 1); |
+ __ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); |
+ |
+ STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
+ LAST_SPEC_OBJECT_TYPE - 1); |
+ __ Branch(&function, eq, a1, Operand(LAST_SPEC_OBJECT_TYPE)); |
+ // Assume that there is no larger type. |
+ STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); |
- // Check if the constructor in the map is a function. |
+ // Check if the constructor in the map is a JS function. |
__ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset)); |
__ GetObjectType(v0, a1, a1); |
__ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE)); |
@@ -3193,10 +3212,16 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { |
// pauses in the middle of scanning a single object. Therefore the |
// incremental marker is not disturbed, so we don't need to call the |
// RecordWrite stub that notifies the incremental marker. |
- __ RememberedSetHelper( |
- index1, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
- __ RememberedSetHelper( |
- index2, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
+ __ RememberedSetHelper(elements, |
+ index1, |
+ scratch2, |
+ kDontSaveFPRegs, |
+ MacroAssembler::kFallThroughAtEnd); |
+ __ RememberedSetHelper(elements, |
+ index2, |
+ scratch2, |
+ kDontSaveFPRegs, |
+ MacroAssembler::kFallThroughAtEnd); |
__ bind(&no_remembered_set); |
// We are done. Drop elements from the stack, and return undefined. |
@@ -4003,10 +4028,11 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); |
} else if (check->Equals(isolate()->heap()->function_symbol())) { |
__ JumpIfSmi(v0, if_false); |
- __ GetObjectType(v0, a1, v0); // Leave map in a1. |
- Split(ge, v0, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE), |
- if_true, if_false, fall_through); |
- |
+ STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
+ __ GetObjectType(v0, v0, a1); |
+ __ Branch(if_true, eq, a1, Operand(JS_FUNCTION_TYPE)); |
+ Split(eq, a1, Operand(JS_FUNCTION_PROXY_TYPE), |
+ if_true, if_false, fall_through); |
} else if (check->Equals(isolate()->heap()->object_symbol())) { |
__ JumpIfSmi(v0, if_false); |
if (!FLAG_harmony_typeof) { |