| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "debug.h" | 32 #include "debug.h" |
| 33 #include "scopes.h" | 33 #include "scopes.h" |
| 34 #include "runtime.h" | 34 #include "runtime.h" |
| 35 | 35 |
| 36 namespace v8 { namespace internal { | 36 namespace v8 { namespace internal { |
| 37 | 37 |
| 38 #define __ masm_-> |
| 39 |
| 40 // ------------------------------------------------------------------------- |
| 41 // VirtualFrame implementation. |
| 42 |
| 43 VirtualFrame::VirtualFrame(CodeGenerator* cgen) { |
| 44 ASSERT(cgen->scope() != NULL); |
| 45 |
| 46 masm_ = cgen->masm(); |
| 47 frame_local_count_ = cgen->scope()->num_stack_slots(); |
| 48 parameter_count_ = cgen->scope()->num_parameters(); |
| 49 } |
| 50 |
| 51 |
| 52 void VirtualFrame::Enter() { |
| 53 Comment cmnt(masm_, "[ Enter JS frame"); |
| 54 #ifdef DEBUG |
| 55 { Label done, fail; |
| 56 __ tst(r1, Operand(kSmiTagMask)); |
| 57 __ b(eq, &fail); |
| 58 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 59 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 60 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
| 61 __ b(eq, &done); |
| 62 __ bind(&fail); |
| 63 __ stop("CodeGenerator::EnterJSFrame - r1 not a function"); |
| 64 __ bind(&done); |
| 65 } |
| 66 #endif // DEBUG |
| 67 |
| 68 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| 69 // Adjust FP to point to saved FP. |
| 70 __ add(fp, sp, Operand(2 * kPointerSize)); |
| 71 } |
| 72 |
| 73 |
| 74 void VirtualFrame::Exit() { |
| 75 Comment cmnt(masm_, "[ Exit JS frame"); |
| 76 // Drop the execution stack down to the frame pointer and restore the caller |
| 77 // frame pointer and return address. |
| 78 __ mov(sp, fp); |
| 79 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 80 } |
| 81 |
| 82 |
| 83 void VirtualFrame::AllocateLocals() { |
| 84 if (frame_local_count_ > 0) { |
| 85 Comment cmnt(masm_, "[ Allocate space for locals"); |
| 86 // Initialize stack slots with 'undefined' value. |
| 87 __ mov(ip, Operand(Factory::undefined_value())); |
| 88 for (int i = 0; i < frame_local_count_; i++) { |
| 89 __ push(ip); |
| 90 } |
| 91 } |
| 92 } |
| 93 |
| 94 |
| 95 void VirtualFrame::Drop(int count) { |
| 96 ASSERT(count >= 0); |
| 97 if (count > 0) { |
| 98 __ add(sp, sp, Operand(count * kPointerSize)); |
| 99 } |
| 100 } |
| 101 |
| 102 |
| 103 void VirtualFrame::Pop() { Drop(1); } |
| 104 |
| 105 |
| 106 void VirtualFrame::Pop(Register reg) { |
| 107 __ pop(reg); |
| 108 } |
| 109 |
| 110 |
| 111 void VirtualFrame::Push(Register reg) { |
| 112 __ push(reg); |
| 113 } |
| 114 |
| 115 |
| 38 // ------------------------------------------------------------------------- | 116 // ------------------------------------------------------------------------- |
| 39 // CodeGenState implementation. | 117 // CodeGenState implementation. |
| 40 | 118 |
| 41 CodeGenState::CodeGenState(CodeGenerator* owner) | 119 CodeGenState::CodeGenState(CodeGenerator* owner) |
| 42 : owner_(owner), | 120 : owner_(owner), |
| 43 typeof_state_(NOT_INSIDE_TYPEOF), | 121 typeof_state_(NOT_INSIDE_TYPEOF), |
| 44 true_target_(NULL), | 122 true_target_(NULL), |
| 45 false_target_(NULL), | 123 false_target_(NULL), |
| 46 previous_(NULL) { | 124 previous_(NULL) { |
| 47 owner_->set_state(this); | 125 owner_->set_state(this); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 60 owner_->set_state(this); | 138 owner_->set_state(this); |
| 61 } | 139 } |
| 62 | 140 |
| 63 | 141 |
| 64 CodeGenState::~CodeGenState() { | 142 CodeGenState::~CodeGenState() { |
| 65 ASSERT(owner_->state() == this); | 143 ASSERT(owner_->state() == this); |
| 66 owner_->set_state(previous_); | 144 owner_->set_state(previous_); |
| 67 } | 145 } |
| 68 | 146 |
| 69 | 147 |
| 70 // ----------------------------------------------------------------------------- | 148 // ------------------------------------------------------------------------- |
| 71 // CodeGenerator implementation | 149 // CodeGenerator implementation |
| 72 | 150 |
| 73 #define __ masm_-> | |
| 74 | |
| 75 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, | 151 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
| 76 bool is_eval) | 152 bool is_eval) |
| 77 : is_eval_(is_eval), | 153 : is_eval_(is_eval), |
| 78 script_(script), | 154 script_(script), |
| 79 deferred_(8), | 155 deferred_(8), |
| 80 masm_(new MacroAssembler(NULL, buffer_size)), | 156 masm_(new MacroAssembler(NULL, buffer_size)), |
| 81 scope_(NULL), | 157 scope_(NULL), |
| 158 frame_(NULL), |
| 82 cc_reg_(al), | 159 cc_reg_(al), |
| 83 state_(NULL), | 160 state_(NULL), |
| 84 break_stack_height_(0) { | 161 break_stack_height_(0) { |
| 85 } | 162 } |
| 86 | 163 |
| 87 | 164 |
| 88 // Calling conventions: | 165 // Calling conventions: |
| 89 | |
| 90 // r0: the number of arguments | 166 // r0: the number of arguments |
| 91 // fp: frame pointer | 167 // fp: frame pointer |
| 92 // sp: stack pointer | 168 // sp: stack pointer |
| 93 // pp: caller's parameter pointer | 169 // pp: caller's parameter pointer |
| 94 // cp: callee's context | 170 // cp: callee's context |
| 95 | 171 |
| 96 void CodeGenerator::GenCode(FunctionLiteral* fun) { | 172 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
| 97 Scope* scope = fun->scope(); | |
| 98 ZoneList<Statement*>* body = fun->body(); | 173 ZoneList<Statement*>* body = fun->body(); |
| 99 | 174 |
| 100 // Initialize state. | 175 // Initialize state. |
| 101 { CodeGenState state(this); | 176 ASSERT(scope_ == NULL); |
| 102 scope_ = scope; | 177 scope_ = fun->scope(); |
| 103 cc_reg_ = al; | 178 ASSERT(frame_ == NULL); |
| 179 VirtualFrame virtual_frame(this); |
| 180 frame_ = &virtual_frame; |
| 181 cc_reg_ = al; |
| 182 { |
| 183 CodeGenState state(this); |
| 104 | 184 |
| 105 // Entry | 185 // Entry |
| 106 // stack: function, receiver, arguments, return address | 186 // stack: function, receiver, arguments, return address |
| 107 // r0: number of arguments | 187 // r0: number of arguments |
| 108 // sp: stack pointer | 188 // sp: stack pointer |
| 109 // fp: frame pointer | 189 // fp: frame pointer |
| 110 // pp: caller's parameter pointer | 190 // pp: caller's parameter pointer |
| 111 // cp: callee's context | 191 // cp: callee's context |
| 112 | 192 |
| 113 { Comment cmnt(masm_, "[ enter JS frame"); | 193 frame_->Enter(); |
| 114 EnterJSFrame(); | |
| 115 } | |
| 116 // tos: code slot | 194 // tos: code slot |
| 117 #ifdef DEBUG | 195 #ifdef DEBUG |
| 118 if (strlen(FLAG_stop_at) > 0 && | 196 if (strlen(FLAG_stop_at) > 0 && |
| 119 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 197 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 120 __ stop("stop-at"); | 198 __ stop("stop-at"); |
| 121 } | 199 } |
| 122 #endif | 200 #endif |
| 123 | 201 |
| 124 // Allocate space for locals and initialize them. | 202 // Allocate space for locals and initialize them. |
| 125 if (scope->num_stack_slots() > 0) { | 203 frame_->AllocateLocals(); |
| 126 Comment cmnt(masm_, "[ allocate space for locals"); | |
| 127 // Initialize stack slots with 'undefined' value. | |
| 128 __ mov(ip, Operand(Factory::undefined_value())); | |
| 129 for (int i = 0; i < scope->num_stack_slots(); i++) { | |
| 130 __ push(ip); | |
| 131 } | |
| 132 } | |
| 133 | 204 |
| 134 if (scope->num_heap_slots() > 0) { | 205 if (scope_->num_heap_slots() > 0) { |
| 135 // Allocate local context. | 206 // Allocate local context. |
| 136 // Get outer context and create a new context based on it. | 207 // Get outer context and create a new context based on it. |
| 137 __ ldr(r0, FunctionOperand()); | 208 __ ldr(r0, frame_->Function()); |
| 138 __ push(r0); | 209 frame_->Push(r0); |
| 139 __ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result | 210 __ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result |
| 140 | 211 |
| 141 if (kDebug) { | 212 if (kDebug) { |
| 142 Label verified_true; | 213 Label verified_true; |
| 143 __ cmp(r0, Operand(cp)); | 214 __ cmp(r0, Operand(cp)); |
| 144 __ b(eq, &verified_true); | 215 __ b(eq, &verified_true); |
| 145 __ stop("NewContext: r0 is expected to be the same as cp"); | 216 __ stop("NewContext: r0 is expected to be the same as cp"); |
| 146 __ bind(&verified_true); | 217 __ bind(&verified_true); |
| 147 } | 218 } |
| 148 // Update context local. | 219 // Update context local. |
| 149 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 220 __ str(cp, frame_->Context()); |
| 150 } | 221 } |
| 151 | 222 |
| 152 // TODO(1241774): Improve this code!!! | 223 // TODO(1241774): Improve this code: |
| 153 // 1) only needed if we have a context | 224 // 1) only needed if we have a context |
| 154 // 2) no need to recompute context ptr every single time | 225 // 2) no need to recompute context ptr every single time |
| 155 // 3) don't copy parameter operand code from SlotOperand! | 226 // 3) don't copy parameter operand code from SlotOperand! |
| 156 { | 227 { |
| 157 Comment cmnt2(masm_, "[ copy context parameters into .context"); | 228 Comment cmnt2(masm_, "[ copy context parameters into .context"); |
| 158 | 229 |
| 159 // Note that iteration order is relevant here! If we have the same | 230 // Note that iteration order is relevant here! If we have the same |
| 160 // parameter twice (e.g., function (x, y, x)), and that parameter | 231 // parameter twice (e.g., function (x, y, x)), and that parameter |
| 161 // needs to be copied into the context, it must be the last argument | 232 // needs to be copied into the context, it must be the last argument |
| 162 // passed to the parameter that needs to be copied. This is a rare | 233 // passed to the parameter that needs to be copied. This is a rare |
| 163 // case so we don't check for it, instead we rely on the copying | 234 // case so we don't check for it, instead we rely on the copying |
| 164 // order: such a parameter is copied repeatedly into the same | 235 // order: such a parameter is copied repeatedly into the same |
| 165 // context location and thus the last value is what is seen inside | 236 // context location and thus the last value is what is seen inside |
| 166 // the function. | 237 // the function. |
| 167 for (int i = 0; i < scope->num_parameters(); i++) { | 238 for (int i = 0; i < scope_->num_parameters(); i++) { |
| 168 Variable* par = scope->parameter(i); | 239 Variable* par = scope_->parameter(i); |
| 169 Slot* slot = par->slot(); | 240 Slot* slot = par->slot(); |
| 170 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 241 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 171 ASSERT(!scope->is_global_scope()); // no parameters in global scope | 242 ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
| 172 __ ldr(r1, ParameterOperand(i)); | 243 __ ldr(r1, frame_->Parameter(i)); |
| 173 // Loads r2 with context; used below in RecordWrite. | 244 // Loads r2 with context; used below in RecordWrite. |
| 174 __ str(r1, SlotOperand(slot, r2)); | 245 __ str(r1, SlotOperand(slot, r2)); |
| 175 // Load the offset into r3. | 246 // Load the offset into r3. |
| 176 int slot_offset = | 247 int slot_offset = |
| 177 FixedArray::kHeaderSize + slot->index() * kPointerSize; | 248 FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 178 __ mov(r3, Operand(slot_offset)); | 249 __ mov(r3, Operand(slot_offset)); |
| 179 __ RecordWrite(r2, r3, r1); | 250 __ RecordWrite(r2, r3, r1); |
| 180 } | 251 } |
| 181 } | 252 } |
| 182 } | 253 } |
| 183 | 254 |
| 184 // Store the arguments object. | 255 // Store the arguments object. This must happen after context |
| 185 // This must happen after context initialization because | 256 // initialization because the arguments object may be stored in the |
| 186 // the arguments array may be stored in the context! | 257 // context. |
| 187 if (scope->arguments() != NULL) { | 258 if (scope_->arguments() != NULL) { |
| 188 ASSERT(scope->arguments_shadow() != NULL); | 259 ASSERT(scope_->arguments_shadow() != NULL); |
| 189 Comment cmnt(masm_, "[ allocate arguments object"); | 260 Comment cmnt(masm_, "[ allocate arguments object"); |
| 190 { Reference shadow_ref(this, scope->arguments_shadow()); | 261 { Reference shadow_ref(this, scope_->arguments_shadow()); |
| 191 { Reference arguments_ref(this, scope->arguments()); | 262 { Reference arguments_ref(this, scope_->arguments()); |
| 192 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 263 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 193 __ ldr(r2, FunctionOperand()); | 264 __ ldr(r2, frame_->Function()); |
| 194 // The receiver is below the arguments, the return address, | 265 // The receiver is below the arguments, the return address, |
| 195 // and the frame pointer on the stack. | 266 // and the frame pointer on the stack. |
| 196 const int kReceiverDisplacement = 2 + scope->num_parameters(); | 267 const int kReceiverDisplacement = 2 + scope_->num_parameters(); |
| 197 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); | 268 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); |
| 198 __ mov(r0, Operand(Smi::FromInt(scope->num_parameters()))); | 269 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| 199 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); | 270 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); |
| 200 __ CallStub(&stub); | 271 __ CallStub(&stub); |
| 201 __ push(r0); | 272 frame_->Push(r0); |
| 202 arguments_ref.SetValue(NOT_CONST_INIT); | 273 arguments_ref.SetValue(NOT_CONST_INIT); |
| 203 } | 274 } |
| 204 shadow_ref.SetValue(NOT_CONST_INIT); | 275 shadow_ref.SetValue(NOT_CONST_INIT); |
| 205 } | 276 } |
| 206 __ pop(r0); // Value is no longer needed. | 277 frame_->Pop(); // Value is no longer needed. |
| 207 } | 278 } |
| 208 | 279 |
| 209 // Generate code to 'execute' declarations and initialize | 280 // Generate code to 'execute' declarations and initialize functions |
| 210 // functions (source elements). In case of an illegal | 281 // (source elements). In case of an illegal redeclaration we need to |
| 211 // redeclaration we need to handle that instead of processing the | 282 // handle that instead of processing the declarations. |
| 212 // declarations. | 283 if (scope_->HasIllegalRedeclaration()) { |
| 213 if (scope->HasIllegalRedeclaration()) { | |
| 214 Comment cmnt(masm_, "[ illegal redeclarations"); | 284 Comment cmnt(masm_, "[ illegal redeclarations"); |
| 215 scope->VisitIllegalRedeclaration(this); | 285 scope_->VisitIllegalRedeclaration(this); |
| 216 } else { | 286 } else { |
| 217 Comment cmnt(masm_, "[ declarations"); | 287 Comment cmnt(masm_, "[ declarations"); |
| 218 // ProcessDeclarations calls DeclareGlobals indirectly | 288 ProcessDeclarations(scope_->declarations()); |
| 219 ProcessDeclarations(scope->declarations()); | 289 // Bail out if a stack-overflow exception occurred when processing |
| 220 | 290 // declarations. |
| 221 // Bail out if a stack-overflow exception occurred when | |
| 222 // processing declarations. | |
| 223 if (HasStackOverflow()) return; | 291 if (HasStackOverflow()) return; |
| 224 } | 292 } |
| 225 | 293 |
| 226 if (FLAG_trace) { | 294 if (FLAG_trace) { |
| 227 // Push a valid value as the parameter. The runtime call only uses | |
| 228 // it as the return value to indicate non-failure. | |
| 229 __ CallRuntime(Runtime::kTraceEnter, 0); | 295 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 296 // Ignore the return value. |
| 230 } | 297 } |
| 231 CheckStack(); | 298 CheckStack(); |
| 232 | 299 |
| 233 // Compile the body of the function in a vanilla state. Don't | 300 // Compile the body of the function in a vanilla state. Don't |
| 234 // bother compiling all the code if the scope has an illegal | 301 // bother compiling all the code if the scope has an illegal |
| 235 // redeclaration. | 302 // redeclaration. |
| 236 if (!scope->HasIllegalRedeclaration()) { | 303 if (!scope_->HasIllegalRedeclaration()) { |
| 237 Comment cmnt(masm_, "[ function body"); | 304 Comment cmnt(masm_, "[ function body"); |
| 238 #ifdef DEBUG | 305 #ifdef DEBUG |
| 239 bool is_builtin = Bootstrapper::IsActive(); | 306 bool is_builtin = Bootstrapper::IsActive(); |
| 240 bool should_trace = | 307 bool should_trace = |
| 241 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; | 308 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; |
| 242 if (should_trace) { | 309 if (should_trace) { |
| 243 __ CallRuntime(Runtime::kDebugTrace, 0); | 310 __ CallRuntime(Runtime::kDebugTrace, 0); |
| 311 // Ignore the return value. |
| 244 } | 312 } |
| 245 #endif | 313 #endif |
| 246 VisitStatements(body); | 314 VisitStatements(body); |
| 247 } | 315 } |
| 248 } | 316 } |
| 249 | 317 |
| 250 // exit | 318 // exit |
| 251 // r0: result | 319 // r0: result |
| 252 // sp: stack pointer | 320 // sp: stack pointer |
| 253 // fp: frame pointer | 321 // fp: frame pointer |
| 254 // pp: parameter pointer | 322 // pp: parameter pointer |
| 255 // cp: callee's context | 323 // cp: callee's context |
| 256 __ mov(r0, Operand(Factory::undefined_value())); | 324 __ mov(r0, Operand(Factory::undefined_value())); |
| 257 | 325 |
| 258 __ bind(&function_return_); | 326 __ bind(&function_return_); |
| 259 if (FLAG_trace) { | 327 if (FLAG_trace) { |
| 260 // Push the return value on the stack as the parameter. | 328 // Push the return value on the stack as the parameter. |
| 261 // Runtime::TraceExit returns the parameter as it is. | 329 // Runtime::TraceExit returns the parameter as it is. |
| 262 __ push(r0); | 330 frame_->Push(r0); |
| 263 __ CallRuntime(Runtime::kTraceExit, 1); | 331 __ CallRuntime(Runtime::kTraceExit, 1); |
| 264 } | 332 } |
| 265 | 333 |
| 266 // Tear down the frame which will restore the caller's frame pointer and the | 334 // Tear down the frame which will restore the caller's frame pointer and the |
| 267 // link register. | 335 // link register. |
| 268 ExitJSFrame(); | 336 frame_->Exit(); |
| 269 | 337 |
| 270 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); | 338 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); |
| 271 __ mov(pc, lr); | 339 __ mov(pc, lr); |
| 272 | 340 |
| 273 // Code generation state must be reset. | 341 // Code generation state must be reset. |
| 274 scope_ = NULL; | 342 scope_ = NULL; |
| 343 frame_ = NULL; |
| 275 ASSERT(!has_cc()); | 344 ASSERT(!has_cc()); |
| 276 ASSERT(state_ == NULL); | 345 ASSERT(state_ == NULL); |
| 277 } | 346 } |
| 278 | 347 |
| 279 | 348 |
| 280 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 349 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| 281 // Currently, this assertion will fail if we try to assign to | 350 // Currently, this assertion will fail if we try to assign to |
| 282 // a constant variable that is constant because it is read-only | 351 // a constant variable that is constant because it is read-only |
| 283 // (such as the variable referring to a named function expression). | 352 // (such as the variable referring to a named function expression). |
| 284 // We need to implement assignments to read-only variables. | 353 // We need to implement assignments to read-only variables. |
| 285 // Ideally, we should do this during AST generation (by converting | 354 // Ideally, we should do this during AST generation (by converting |
| 286 // such assignments into expression statements); however, in general | 355 // such assignments into expression statements); however, in general |
| 287 // we may not be able to make the decision until past AST generation, | 356 // we may not be able to make the decision until past AST generation, |
| 288 // that is when the entire program is known. | 357 // that is when the entire program is known. |
| 289 ASSERT(slot != NULL); | 358 ASSERT(slot != NULL); |
| 290 int index = slot->index(); | 359 int index = slot->index(); |
| 291 switch (slot->type()) { | 360 switch (slot->type()) { |
| 292 case Slot::PARAMETER: | 361 case Slot::PARAMETER: |
| 293 return ParameterOperand(index); | 362 return frame_->Parameter(index); |
| 294 | 363 |
| 295 case Slot::LOCAL: { | 364 case Slot::LOCAL: |
| 296 ASSERT(0 <= index && index < scope()->num_stack_slots()); | 365 return frame_->Local(index); |
| 297 const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset; | |
| 298 return MemOperand(fp, kLocalOffset - index * kPointerSize); | |
| 299 } | |
| 300 | 366 |
| 301 case Slot::CONTEXT: { | 367 case Slot::CONTEXT: { |
| 302 // Follow the context chain if necessary. | 368 // Follow the context chain if necessary. |
| 303 ASSERT(!tmp.is(cp)); // do not overwrite context register | 369 ASSERT(!tmp.is(cp)); // do not overwrite context register |
| 304 Register context = cp; | 370 Register context = cp; |
| 305 int chain_length = scope()->ContextChainLength(slot->var()->scope()); | 371 int chain_length = scope()->ContextChainLength(slot->var()->scope()); |
| 306 for (int i = chain_length; i-- > 0;) { | 372 for (int i = chain_length; i-- > 0;) { |
| 307 // Load the closure. | 373 // Load the closure. |
| 308 // (All contexts, even 'with' contexts, have a closure, | 374 // (All contexts, even 'with' contexts, have a closure, |
| 309 // and it is the same for all contexts inside a function. | 375 // and it is the same for all contexts inside a function. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 324 return ContextOperand(tmp, index); | 390 return ContextOperand(tmp, index); |
| 325 } | 391 } |
| 326 | 392 |
| 327 default: | 393 default: |
| 328 UNREACHABLE(); | 394 UNREACHABLE(); |
| 329 return MemOperand(r0, 0); | 395 return MemOperand(r0, 0); |
| 330 } | 396 } |
| 331 } | 397 } |
| 332 | 398 |
| 333 | 399 |
| 334 // Loads a value on the stack. If it is a boolean value, the result may have | 400 // Loads a value on TOS. If it is a boolean value, the result may have been |
| 335 // been (partially) translated into branches, or it may have set the condition | 401 // (partially) translated into branches, or it may have set the condition |
| 336 // code register. If force_cc is set, the value is forced to set the condition | 402 // code register. If force_cc is set, the value is forced to set the |
| 337 // code register and no value is pushed. If the condition code register was set, | 403 // condition code register and no value is pushed. If the condition code |
| 338 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 404 // register was set, has_cc() is true and cc_reg_ contains the condition to |
| 405 // test for 'true'. |
| 339 void CodeGenerator::LoadCondition(Expression* x, | 406 void CodeGenerator::LoadCondition(Expression* x, |
| 340 TypeofState typeof_state, | 407 TypeofState typeof_state, |
| 341 Label* true_target, | 408 Label* true_target, |
| 342 Label* false_target, | 409 Label* false_target, |
| 343 bool force_cc) { | 410 bool force_cc) { |
| 344 ASSERT(!has_cc()); | 411 ASSERT(!has_cc()); |
| 345 | 412 |
| 346 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 413 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 347 Visit(x); | 414 Visit(x); |
| 348 } | 415 } |
| 349 if (force_cc && !has_cc()) { | 416 if (force_cc && !has_cc()) { |
| 350 // Convert the TOS value to a boolean in the condition code register. | 417 // Convert the TOS value to a boolean in the condition code register. |
| 418 // Visiting an expression may possibly choose neither (a) to leave a |
| 419 // value in the condition code register nor (b) to leave a value in TOS |
| 420 // (eg, by compiling to only jumps to the targets). In that case the |
| 421 // code generated by ToBoolean is wrong because it assumes the value of |
| 422 // the expression in TOS. So long as there is always a value in TOS or |
| 423 // the condition code register when control falls through to here (there |
| 424 // is), the code generated by ToBoolean is dead and therefore safe. |
| 351 ToBoolean(true_target, false_target); | 425 ToBoolean(true_target, false_target); |
| 352 } | 426 } |
| 353 ASSERT(has_cc() || !force_cc); | 427 ASSERT(has_cc() || !force_cc); |
| 354 } | 428 } |
| 355 | 429 |
| 356 | 430 |
| 357 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 431 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 358 Label true_target; | 432 Label true_target; |
| 359 Label false_target; | 433 Label false_target; |
| 360 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 434 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 361 | 435 |
| 362 if (has_cc()) { | 436 if (has_cc()) { |
| 363 // convert cc_reg_ into a bool | 437 // convert cc_reg_ into a bool |
| 364 Label loaded, materialize_true; | 438 Label loaded, materialize_true; |
| 365 __ b(cc_reg_, &materialize_true); | 439 __ b(cc_reg_, &materialize_true); |
| 366 __ mov(r0, Operand(Factory::false_value())); | 440 __ mov(r0, Operand(Factory::false_value())); |
| 367 __ push(r0); | 441 frame_->Push(r0); |
| 368 __ b(&loaded); | 442 __ b(&loaded); |
| 369 __ bind(&materialize_true); | 443 __ bind(&materialize_true); |
| 370 __ mov(r0, Operand(Factory::true_value())); | 444 __ mov(r0, Operand(Factory::true_value())); |
| 371 __ push(r0); | 445 frame_->Push(r0); |
| 372 __ bind(&loaded); | 446 __ bind(&loaded); |
| 373 cc_reg_ = al; | 447 cc_reg_ = al; |
| 374 } | 448 } |
| 375 | 449 |
| 376 if (true_target.is_linked() || false_target.is_linked()) { | 450 if (true_target.is_linked() || false_target.is_linked()) { |
| 377 // we have at least one condition value | 451 // we have at least one condition value |
| 378 // that has been "translated" into a branch, | 452 // that has been "translated" into a branch, |
| 379 // thus it needs to be loaded explicitly again | 453 // thus it needs to be loaded explicitly again |
| 380 Label loaded; | 454 Label loaded; |
| 381 __ b(&loaded); // don't lose current TOS | 455 __ b(&loaded); // don't lose current TOS |
| 382 bool both = true_target.is_linked() && false_target.is_linked(); | 456 bool both = true_target.is_linked() && false_target.is_linked(); |
| 383 // reincarnate "true", if necessary | 457 // reincarnate "true", if necessary |
| 384 if (true_target.is_linked()) { | 458 if (true_target.is_linked()) { |
| 385 __ bind(&true_target); | 459 __ bind(&true_target); |
| 386 __ mov(r0, Operand(Factory::true_value())); | 460 __ mov(r0, Operand(Factory::true_value())); |
| 387 __ push(r0); | 461 frame_->Push(r0); |
| 388 } | 462 } |
| 389 // if both "true" and "false" need to be reincarnated, | 463 // if both "true" and "false" need to be reincarnated, |
| 390 // jump across code for "false" | 464 // jump across code for "false" |
| 391 if (both) | 465 if (both) |
| 392 __ b(&loaded); | 466 __ b(&loaded); |
| 393 // reincarnate "false", if necessary | 467 // reincarnate "false", if necessary |
| 394 if (false_target.is_linked()) { | 468 if (false_target.is_linked()) { |
| 395 __ bind(&false_target); | 469 __ bind(&false_target); |
| 396 __ mov(r0, Operand(Factory::false_value())); | 470 __ mov(r0, Operand(Factory::false_value())); |
| 397 __ push(r0); | 471 frame_->Push(r0); |
| 398 } | 472 } |
| 399 // everything is loaded at this point | 473 // everything is loaded at this point |
| 400 __ bind(&loaded); | 474 __ bind(&loaded); |
| 401 } | 475 } |
| 402 ASSERT(!has_cc()); | 476 ASSERT(!has_cc()); |
| 403 } | 477 } |
| 404 | 478 |
| 405 | 479 |
| 406 void CodeGenerator::LoadGlobal() { | 480 void CodeGenerator::LoadGlobal() { |
| 407 __ ldr(r0, GlobalObject()); | 481 __ ldr(r0, GlobalObject()); |
| 408 __ push(r0); | 482 frame_->Push(r0); |
| 409 } | 483 } |
| 410 | 484 |
| 411 | 485 |
| 412 void CodeGenerator::LoadGlobalReceiver(Register s) { | 486 void CodeGenerator::LoadGlobalReceiver(Register scratch) { |
| 413 __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX)); | 487 __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX)); |
| 414 __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset)); | 488 __ ldr(scratch, |
| 415 __ push(s); | 489 FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset)); |
| 490 frame_->Push(scratch); |
| 416 } | 491 } |
| 417 | 492 |
| 418 | 493 |
| 419 // TODO(1241834): Get rid of this function in favor of just using Load, now | 494 // TODO(1241834): Get rid of this function in favor of just using Load, now |
| 420 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global | 495 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
| 421 // variables w/o reference errors elsewhere. | 496 // variables w/o reference errors elsewhere. |
| 422 void CodeGenerator::LoadTypeofExpression(Expression* x) { | 497 void CodeGenerator::LoadTypeofExpression(Expression* x) { |
| 423 Variable* variable = x->AsVariableProxy()->AsVariable(); | 498 Variable* variable = x->AsVariableProxy()->AsVariable(); |
| 424 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 499 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
| 425 // NOTE: This is somewhat nasty. We force the compiler to load | 500 // NOTE: This is somewhat nasty. We force the compiler to load |
| (...skipping 17 matching lines...) Expand all Loading... |
| 443 } | 518 } |
| 444 | 519 |
| 445 | 520 |
| 446 Reference::~Reference() { | 521 Reference::~Reference() { |
| 447 cgen_->UnloadReference(this); | 522 cgen_->UnloadReference(this); |
| 448 } | 523 } |
| 449 | 524 |
| 450 | 525 |
| 451 void CodeGenerator::LoadReference(Reference* ref) { | 526 void CodeGenerator::LoadReference(Reference* ref) { |
| 452 Comment cmnt(masm_, "[ LoadReference"); | 527 Comment cmnt(masm_, "[ LoadReference"); |
| 453 | |
| 454 Expression* e = ref->expression(); | 528 Expression* e = ref->expression(); |
| 455 Property* property = e->AsProperty(); | 529 Property* property = e->AsProperty(); |
| 456 Variable* var = e->AsVariableProxy()->AsVariable(); | 530 Variable* var = e->AsVariableProxy()->AsVariable(); |
| 457 | 531 |
| 458 if (property != NULL) { | 532 if (property != NULL) { |
| 459 // The expression is either a property or a variable proxy that rewrites | 533 // The expression is either a property or a variable proxy that rewrites |
| 460 // to a property. | 534 // to a property. |
| 461 Load(property->obj()); | 535 Load(property->obj()); |
| 462 // We use a named reference if the key is a literal symbol, unless it is | 536 // We use a named reference if the key is a literal symbol, unless it is |
| 463 // a string that can be legally parsed as an integer. This is because | 537 // a string that can be legally parsed as an integer. This is because |
| (...skipping 21 matching lines...) Expand all Loading... |
| 485 } | 559 } |
| 486 } else { | 560 } else { |
| 487 // Anything else is a runtime error. | 561 // Anything else is a runtime error. |
| 488 Load(e); | 562 Load(e); |
| 489 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 563 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 490 } | 564 } |
| 491 } | 565 } |
| 492 | 566 |
| 493 | 567 |
| 494 void CodeGenerator::UnloadReference(Reference* ref) { | 568 void CodeGenerator::UnloadReference(Reference* ref) { |
| 569 // Pop a reference from the stack while preserving TOS. |
| 495 Comment cmnt(masm_, "[ UnloadReference"); | 570 Comment cmnt(masm_, "[ UnloadReference"); |
| 496 | |
| 497 int size = ref->size(); | 571 int size = ref->size(); |
| 498 if (size <= 0) { | 572 if (size > 0) { |
| 499 // Do nothing. No popping is necessary. | 573 frame_->Pop(r0); |
| 500 } else { | 574 frame_->Drop(size); |
| 501 __ pop(r0); | 575 frame_->Push(r0); |
| 502 __ add(sp, sp, Operand(size * kPointerSize)); | |
| 503 __ push(r0); | |
| 504 } | 576 } |
| 505 } | 577 } |
| 506 | 578 |
| 507 | 579 |
| 508 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 580 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given |
| 509 // register to a boolean in the condition code register. The code | 581 // register to a boolean in the condition code register. The code |
| 510 // may jump to 'false_target' in case the register converts to 'false'. | 582 // may jump to 'false_target' in case the register converts to 'false'. |
| 511 void CodeGenerator::ToBoolean(Label* true_target, | 583 void CodeGenerator::ToBoolean(Label* true_target, |
| 512 Label* false_target) { | 584 Label* false_target) { |
| 513 // Note: The generated code snippet does not change stack variables. | 585 // Note: The generated code snippet does not change stack variables. |
| 514 // Only the condition code should be set. | 586 // Only the condition code should be set. |
| 515 __ pop(r0); | 587 frame_->Pop(r0); |
| 516 | 588 |
| 517 // Fast case checks | 589 // Fast case checks |
| 518 | 590 |
| 519 // Check if the value is 'false'. | 591 // Check if the value is 'false'. |
| 520 __ cmp(r0, Operand(Factory::false_value())); | 592 __ cmp(r0, Operand(Factory::false_value())); |
| 521 __ b(eq, false_target); | 593 __ b(eq, false_target); |
| 522 | 594 |
| 523 // Check if the value is 'true'. | 595 // Check if the value is 'true'. |
| 524 __ cmp(r0, Operand(Factory::true_value())); | 596 __ cmp(r0, Operand(Factory::true_value())); |
| 525 __ b(eq, true_target); | 597 __ b(eq, true_target); |
| 526 | 598 |
| 527 // Check if the value is 'undefined'. | 599 // Check if the value is 'undefined'. |
| 528 __ cmp(r0, Operand(Factory::undefined_value())); | 600 __ cmp(r0, Operand(Factory::undefined_value())); |
| 529 __ b(eq, false_target); | 601 __ b(eq, false_target); |
| 530 | 602 |
| 531 // Check if the value is a smi. | 603 // Check if the value is a smi. |
| 532 __ cmp(r0, Operand(Smi::FromInt(0))); | 604 __ cmp(r0, Operand(Smi::FromInt(0))); |
| 533 __ b(eq, false_target); | 605 __ b(eq, false_target); |
| 534 __ tst(r0, Operand(kSmiTagMask)); | 606 __ tst(r0, Operand(kSmiTagMask)); |
| 535 __ b(eq, true_target); | 607 __ b(eq, true_target); |
| 536 | 608 |
| 537 // Slow case: call the runtime. | 609 // Slow case: call the runtime. |
| 538 __ push(r0); | 610 frame_->Push(r0); |
| 539 __ CallRuntime(Runtime::kToBool, 1); | 611 __ CallRuntime(Runtime::kToBool, 1); |
| 540 | 612 // Convert the result (r0) to a condition code. |
| 541 // Convert result (r0) to condition code | |
| 542 __ cmp(r0, Operand(Factory::false_value())); | 613 __ cmp(r0, Operand(Factory::false_value())); |
| 543 | 614 |
| 544 cc_reg_ = ne; | 615 cc_reg_ = ne; |
| 545 } | 616 } |
| 546 | 617 |
| 547 | 618 |
| 548 class GetPropertyStub : public CodeStub { | 619 class GetPropertyStub : public CodeStub { |
| 549 public: | 620 public: |
| 550 GetPropertyStub() { } | 621 GetPropertyStub() { } |
| 551 | 622 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 switch (op) { | 703 switch (op) { |
| 633 case Token::ADD: // fall through. | 704 case Token::ADD: // fall through. |
| 634 case Token::SUB: // fall through. | 705 case Token::SUB: // fall through. |
| 635 case Token::MUL: | 706 case Token::MUL: |
| 636 case Token::BIT_OR: | 707 case Token::BIT_OR: |
| 637 case Token::BIT_AND: | 708 case Token::BIT_AND: |
| 638 case Token::BIT_XOR: | 709 case Token::BIT_XOR: |
| 639 case Token::SHL: | 710 case Token::SHL: |
| 640 case Token::SHR: | 711 case Token::SHR: |
| 641 case Token::SAR: { | 712 case Token::SAR: { |
| 642 __ pop(r0); // r0 : y | 713 frame_->Pop(r0); // r0 : y |
| 643 __ pop(r1); // r1 : x | 714 frame_->Pop(r1); // r1 : x |
| 644 GenericBinaryOpStub stub(op); | 715 GenericBinaryOpStub stub(op); |
| 645 __ CallStub(&stub); | 716 __ CallStub(&stub); |
| 646 break; | 717 break; |
| 647 } | 718 } |
| 648 | 719 |
| 649 case Token::DIV: { | 720 case Token::DIV: { |
| 650 __ mov(r0, Operand(1)); | 721 __ mov(r0, Operand(1)); |
| 651 __ InvokeBuiltin(Builtins::DIV, CALL_JS); | 722 __ InvokeBuiltin(Builtins::DIV, CALL_JS); |
| 652 break; | 723 break; |
| 653 } | 724 } |
| 654 | 725 |
| 655 case Token::MOD: { | 726 case Token::MOD: { |
| 656 __ mov(r0, Operand(1)); | 727 __ mov(r0, Operand(1)); |
| 657 __ InvokeBuiltin(Builtins::MOD, CALL_JS); | 728 __ InvokeBuiltin(Builtins::MOD, CALL_JS); |
| 658 break; | 729 break; |
| 659 } | 730 } |
| 660 | 731 |
| 661 case Token::COMMA: | 732 case Token::COMMA: |
| 662 __ pop(r0); | 733 frame_->Pop(r0); |
| 663 // simply discard left value | 734 // simply discard left value |
| 664 __ pop(); | 735 frame_->Pop(); |
| 665 break; | 736 break; |
| 666 | 737 |
| 667 default: | 738 default: |
| 668 // Other cases should have been handled before this point. | 739 // Other cases should have been handled before this point. |
| 669 UNREACHABLE(); | 740 UNREACHABLE(); |
| 670 break; | 741 break; |
| 671 } | 742 } |
| 672 } | 743 } |
| 673 | 744 |
| 674 | 745 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 } | 813 } |
| 743 | 814 |
| 744 private: | 815 private: |
| 745 Token::Value op_; | 816 Token::Value op_; |
| 746 int value_; | 817 int value_; |
| 747 bool reversed_; | 818 bool reversed_; |
| 748 }; | 819 }; |
| 749 | 820 |
| 750 | 821 |
| 751 void CodeGenerator::SmiOperation(Token::Value op, | 822 void CodeGenerator::SmiOperation(Token::Value op, |
| 752 Handle<Object> value, | 823 Handle<Object> value, |
| 753 bool reversed) { | 824 bool reversed) { |
| 754 // NOTE: This is an attempt to inline (a bit) more of the code for | 825 // NOTE: This is an attempt to inline (a bit) more of the code for |
| 755 // some possible smi operations (like + and -) when (at least) one | 826 // some possible smi operations (like + and -) when (at least) one |
| 756 // of the operands is a literal smi. With this optimization, the | 827 // of the operands is a literal smi. With this optimization, the |
| 757 // performance of the system is increased by ~15%, and the generated | 828 // performance of the system is increased by ~15%, and the generated |
| 758 // code size is increased by ~1% (measured on a combination of | 829 // code size is increased by ~1% (measured on a combination of |
| 759 // different benchmarks). | 830 // different benchmarks). |
| 760 | 831 |
| 761 // sp[0] : operand | 832 // sp[0] : operand |
| 762 | 833 |
| 763 int int_value = Smi::cast(*value)->value(); | 834 int int_value = Smi::cast(*value)->value(); |
| 764 | 835 |
| 765 Label exit; | 836 Label exit; |
| 766 __ pop(r0); | 837 frame_->Pop(r0); |
| 767 | 838 |
| 768 switch (op) { | 839 switch (op) { |
| 769 case Token::ADD: { | 840 case Token::ADD: { |
| 770 DeferredCode* deferred = | 841 DeferredCode* deferred = |
| 771 new DeferredInlinedSmiOperation(this, op, int_value, reversed); | 842 new DeferredInlinedSmiOperation(this, op, int_value, reversed); |
| 772 | 843 |
| 773 __ add(r0, r0, Operand(value), SetCC); | 844 __ add(r0, r0, Operand(value), SetCC); |
| 774 __ b(vs, deferred->enter()); | 845 __ b(vs, deferred->enter()); |
| 775 __ tst(r0, Operand(kSmiTagMask)); | 846 __ tst(r0, Operand(kSmiTagMask)); |
| 776 __ b(ne, deferred->enter()); | 847 __ b(ne, deferred->enter()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 } | 880 } |
| 810 __ bind(deferred->exit()); | 881 __ bind(deferred->exit()); |
| 811 break; | 882 break; |
| 812 } | 883 } |
| 813 | 884 |
| 814 case Token::SHL: | 885 case Token::SHL: |
| 815 case Token::SHR: | 886 case Token::SHR: |
| 816 case Token::SAR: { | 887 case Token::SAR: { |
| 817 if (reversed) { | 888 if (reversed) { |
| 818 __ mov(ip, Operand(value)); | 889 __ mov(ip, Operand(value)); |
| 819 __ push(ip); | 890 frame_->Push(ip); |
| 820 __ push(r0); | 891 frame_->Push(r0); |
| 821 GenericBinaryOperation(op); | 892 GenericBinaryOperation(op); |
| 822 | 893 |
| 823 } else { | 894 } else { |
| 824 int shift_value = int_value & 0x1f; // least significant 5 bits | 895 int shift_value = int_value & 0x1f; // least significant 5 bits |
| 825 DeferredCode* deferred = | 896 DeferredCode* deferred = |
| 826 new DeferredInlinedSmiOperation(this, op, shift_value, false); | 897 new DeferredInlinedSmiOperation(this, op, shift_value, false); |
| 827 __ tst(r0, Operand(kSmiTagMask)); | 898 __ tst(r0, Operand(kSmiTagMask)); |
| 828 __ b(ne, deferred->enter()); | 899 __ b(ne, deferred->enter()); |
| 829 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags | 900 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags |
| 830 switch (op) { | 901 switch (op) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 860 default: UNREACHABLE(); | 931 default: UNREACHABLE(); |
| 861 } | 932 } |
| 862 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); | 933 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); |
| 863 __ bind(deferred->exit()); | 934 __ bind(deferred->exit()); |
| 864 } | 935 } |
| 865 break; | 936 break; |
| 866 } | 937 } |
| 867 | 938 |
| 868 default: | 939 default: |
| 869 if (!reversed) { | 940 if (!reversed) { |
| 870 __ push(r0); | 941 frame_->Push(r0); |
| 871 __ mov(r0, Operand(value)); | 942 __ mov(r0, Operand(value)); |
| 872 __ push(r0); | 943 frame_->Push(r0); |
| 873 } else { | 944 } else { |
| 874 __ mov(ip, Operand(value)); | 945 __ mov(ip, Operand(value)); |
| 875 __ push(ip); | 946 frame_->Push(ip); |
| 876 __ push(r0); | 947 frame_->Push(r0); |
| 877 } | 948 } |
| 878 GenericBinaryOperation(op); | 949 GenericBinaryOperation(op); |
| 879 break; | 950 break; |
| 880 } | 951 } |
| 881 | 952 |
| 882 __ bind(&exit); | 953 __ bind(&exit); |
| 883 } | 954 } |
| 884 | 955 |
| 885 | 956 |
| 886 void CodeGenerator::Comparison(Condition cc, bool strict) { | 957 void CodeGenerator::Comparison(Condition cc, bool strict) { |
| 887 // sp[0] : y | 958 // sp[0] : y |
| 888 // sp[1] : x | 959 // sp[1] : x |
| 889 // result : cc register | 960 // result : cc register |
| 890 | 961 |
| 891 // Strict only makes sense for equality comparisons. | 962 // Strict only makes sense for equality comparisons. |
| 892 ASSERT(!strict || cc == eq); | 963 ASSERT(!strict || cc == eq); |
| 893 | 964 |
| 894 Label exit, smi; | 965 Label exit, smi; |
| 895 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 966 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 896 if (cc == gt || cc == le) { | 967 if (cc == gt || cc == le) { |
| 897 cc = ReverseCondition(cc); | 968 cc = ReverseCondition(cc); |
| 898 __ pop(r1); | 969 frame_->Pop(r1); |
| 899 __ pop(r0); | 970 frame_->Pop(r0); |
| 900 } else { | 971 } else { |
| 901 __ pop(r0); | 972 frame_->Pop(r0); |
| 902 __ pop(r1); | 973 frame_->Pop(r1); |
| 903 } | 974 } |
| 904 __ orr(r2, r0, Operand(r1)); | 975 __ orr(r2, r0, Operand(r1)); |
| 905 __ tst(r2, Operand(kSmiTagMask)); | 976 __ tst(r2, Operand(kSmiTagMask)); |
| 906 __ b(eq, &smi); | 977 __ b(eq, &smi); |
| 907 | 978 |
| 908 // Perform non-smi comparison by runtime call. | 979 // Perform non-smi comparison by runtime call. |
| 909 __ push(r1); | 980 frame_->Push(r1); |
| 910 | 981 |
| 911 // Figure out which native to call and setup the arguments. | 982 // Figure out which native to call and setup the arguments. |
| 912 Builtins::JavaScript native; | 983 Builtins::JavaScript native; |
| 913 int argc; | 984 int argc; |
| 914 if (cc == eq) { | 985 if (cc == eq) { |
| 915 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 986 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
| 916 argc = 1; | 987 argc = 1; |
| 917 } else { | 988 } else { |
| 918 native = Builtins::COMPARE; | 989 native = Builtins::COMPARE; |
| 919 int ncr; // NaN compare result | 990 int ncr; // NaN compare result |
| 920 if (cc == lt || cc == le) { | 991 if (cc == lt || cc == le) { |
| 921 ncr = GREATER; | 992 ncr = GREATER; |
| 922 } else { | 993 } else { |
| 923 ASSERT(cc == gt || cc == ge); // remaining cases | 994 ASSERT(cc == gt || cc == ge); // remaining cases |
| 924 ncr = LESS; | 995 ncr = LESS; |
| 925 } | 996 } |
| 926 __ push(r0); | 997 frame_->Push(r0); |
| 927 __ mov(r0, Operand(Smi::FromInt(ncr))); | 998 __ mov(r0, Operand(Smi::FromInt(ncr))); |
| 928 argc = 2; | 999 argc = 2; |
| 929 } | 1000 } |
| 930 | 1001 |
| 931 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 1002 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 932 // tagged as a small integer. | 1003 // tagged as a small integer. |
| 933 __ push(r0); | 1004 frame_->Push(r0); |
| 934 __ mov(r0, Operand(argc)); | 1005 __ mov(r0, Operand(argc)); |
| 935 __ InvokeBuiltin(native, CALL_JS); | 1006 __ InvokeBuiltin(native, CALL_JS); |
| 936 __ cmp(r0, Operand(0)); | 1007 __ cmp(r0, Operand(0)); |
| 937 __ b(&exit); | 1008 __ b(&exit); |
| 938 | 1009 |
| 939 // test smi equality by pointer comparison. | 1010 // test smi equality by pointer comparison. |
| 940 __ bind(&smi); | 1011 __ bind(&smi); |
| 941 __ cmp(r1, Operand(r0)); | 1012 __ cmp(r1, Operand(r0)); |
| 942 | 1013 |
| 943 __ bind(&exit); | 1014 __ bind(&exit); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 972 } | 1043 } |
| 973 | 1044 |
| 974 // Record the position for debugging purposes. | 1045 // Record the position for debugging purposes. |
| 975 __ RecordPosition(position); | 1046 __ RecordPosition(position); |
| 976 | 1047 |
| 977 // Use the shared code stub to call the function. | 1048 // Use the shared code stub to call the function. |
| 978 CallFunctionStub call_function(args->length()); | 1049 CallFunctionStub call_function(args->length()); |
| 979 __ CallStub(&call_function); | 1050 __ CallStub(&call_function); |
| 980 | 1051 |
| 981 // Restore context and pop function from the stack. | 1052 // Restore context and pop function from the stack. |
| 982 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1053 __ ldr(cp, frame_->Context()); |
| 983 __ pop(); // discard the TOS | 1054 frame_->Pop(); // discard the TOS |
| 984 } | 1055 } |
| 985 | 1056 |
| 986 | 1057 |
| 987 void CodeGenerator::Branch(bool if_true, Label* L) { | 1058 void CodeGenerator::Branch(bool if_true, Label* L) { |
| 988 ASSERT(has_cc()); | 1059 ASSERT(has_cc()); |
| 989 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1060 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| 990 __ b(cc, L); | 1061 __ b(cc, L); |
| 991 cc_reg_ = al; | 1062 cc_reg_ = al; |
| 992 } | 1063 } |
| 993 | 1064 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1005 Comment cmnt(masm_, "[ Block"); | 1076 Comment cmnt(masm_, "[ Block"); |
| 1006 if (FLAG_debug_info) RecordStatementPosition(node); | 1077 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1007 node->set_break_stack_height(break_stack_height_); | 1078 node->set_break_stack_height(break_stack_height_); |
| 1008 VisitStatements(node->statements()); | 1079 VisitStatements(node->statements()); |
| 1009 __ bind(node->break_target()); | 1080 __ bind(node->break_target()); |
| 1010 } | 1081 } |
| 1011 | 1082 |
| 1012 | 1083 |
| 1013 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1084 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1014 __ mov(r0, Operand(pairs)); | 1085 __ mov(r0, Operand(pairs)); |
| 1015 __ push(r0); | 1086 frame_->Push(r0); |
| 1016 __ push(cp); | 1087 frame_->Push(cp); |
| 1017 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 1088 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1018 __ push(r0); | 1089 frame_->Push(r0); |
| 1019 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 1090 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1020 // The result is discarded. | 1091 // The result is discarded. |
| 1021 } | 1092 } |
| 1022 | 1093 |
| 1023 | 1094 |
| 1024 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1095 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1025 Comment cmnt(masm_, "[ Declaration"); | 1096 Comment cmnt(masm_, "[ Declaration"); |
| 1026 Variable* var = node->proxy()->var(); | 1097 Variable* var = node->proxy()->var(); |
| 1027 ASSERT(var != NULL); // must have been resolved | 1098 ASSERT(var != NULL); // must have been resolved |
| 1028 Slot* slot = var->slot(); | 1099 Slot* slot = var->slot(); |
| 1029 | 1100 |
| 1030 // If it was not possible to allocate the variable at compile time, | 1101 // If it was not possible to allocate the variable at compile time, |
| 1031 // we need to "declare" it at runtime to make sure it actually | 1102 // we need to "declare" it at runtime to make sure it actually |
| 1032 // exists in the local context. | 1103 // exists in the local context. |
| 1033 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1104 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1034 // Variables with a "LOOKUP" slot were introduced as non-locals | 1105 // Variables with a "LOOKUP" slot were introduced as non-locals |
| 1035 // during variable resolution and must have mode DYNAMIC. | 1106 // during variable resolution and must have mode DYNAMIC. |
| 1036 ASSERT(var->mode() == Variable::DYNAMIC); | 1107 ASSERT(var->mode() == Variable::DYNAMIC); |
| 1037 // For now, just do a runtime call. | 1108 // For now, just do a runtime call. |
| 1038 __ push(cp); | 1109 frame_->Push(cp); |
| 1039 __ mov(r0, Operand(var->name())); | 1110 __ mov(r0, Operand(var->name())); |
| 1040 __ push(r0); | 1111 frame_->Push(r0); |
| 1041 // Declaration nodes are always declared in only two modes. | 1112 // Declaration nodes are always declared in only two modes. |
| 1042 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 1113 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
| 1043 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1114 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| 1044 __ mov(r0, Operand(Smi::FromInt(attr))); | 1115 __ mov(r0, Operand(Smi::FromInt(attr))); |
| 1045 __ push(r0); | 1116 frame_->Push(r0); |
| 1046 // Push initial value, if any. | 1117 // Push initial value, if any. |
| 1047 // Note: For variables we must not push an initial value (such as | 1118 // Note: For variables we must not push an initial value (such as |
| 1048 // 'undefined') because we may have a (legal) redeclaration and we | 1119 // 'undefined') because we may have a (legal) redeclaration and we |
| 1049 // must not destroy the current value. | 1120 // must not destroy the current value. |
| 1050 if (node->mode() == Variable::CONST) { | 1121 if (node->mode() == Variable::CONST) { |
| 1051 __ mov(r0, Operand(Factory::the_hole_value())); | 1122 __ mov(r0, Operand(Factory::the_hole_value())); |
| 1052 __ push(r0); | 1123 frame_->Push(r0); |
| 1053 } else if (node->fun() != NULL) { | 1124 } else if (node->fun() != NULL) { |
| 1054 Load(node->fun()); | 1125 Load(node->fun()); |
| 1055 } else { | 1126 } else { |
| 1056 __ mov(r0, Operand(0)); // no initial value! | 1127 __ mov(r0, Operand(0)); // no initial value! |
| 1057 __ push(r0); | 1128 frame_->Push(r0); |
| 1058 } | 1129 } |
| 1059 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 1130 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 1060 // Ignore the return value (declarations are statements). | 1131 // Ignore the return value (declarations are statements). |
| 1061 return; | 1132 return; |
| 1062 } | 1133 } |
| 1063 | 1134 |
| 1064 ASSERT(!var->is_global()); | 1135 ASSERT(!var->is_global()); |
| 1065 | 1136 |
| 1066 // If we have a function or a constant, we need to initialize the variable. | 1137 // If we have a function or a constant, we need to initialize the variable. |
| 1067 Expression* val = NULL; | 1138 Expression* val = NULL; |
| 1068 if (node->mode() == Variable::CONST) { | 1139 if (node->mode() == Variable::CONST) { |
| 1069 val = new Literal(Factory::the_hole_value()); | 1140 val = new Literal(Factory::the_hole_value()); |
| 1070 } else { | 1141 } else { |
| 1071 val = node->fun(); // NULL if we don't have a function | 1142 val = node->fun(); // NULL if we don't have a function |
| 1072 } | 1143 } |
| 1073 | 1144 |
| 1074 if (val != NULL) { | 1145 if (val != NULL) { |
| 1075 // Set initial value. | 1146 // Set initial value. |
| 1076 Reference target(this, node->proxy()); | 1147 Reference target(this, node->proxy()); |
| 1077 ASSERT(target.is_slot()); | 1148 ASSERT(target.is_slot()); |
| 1078 Load(val); | 1149 Load(val); |
| 1079 target.SetValue(NOT_CONST_INIT); | 1150 target.SetValue(NOT_CONST_INIT); |
| 1080 // Get rid of the assigned value (declarations are statements). It's | 1151 // Get rid of the assigned value (declarations are statements). It's |
| 1081 // safe to pop the value lying on top of the reference before unloading | 1152 // safe to pop the value lying on top of the reference before unloading |
| 1082 // the reference itself (which preserves the top of stack) because we | 1153 // the reference itself (which preserves the top of stack) because we |
| 1083 // know it is a zero-sized reference. | 1154 // know it is a zero-sized reference. |
| 1084 __ pop(); | 1155 frame_->Pop(); |
| 1085 } | 1156 } |
| 1086 } | 1157 } |
| 1087 | 1158 |
| 1088 | 1159 |
| 1089 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1160 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1090 Comment cmnt(masm_, "[ ExpressionStatement"); | 1161 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1091 if (FLAG_debug_info) RecordStatementPosition(node); | 1162 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1092 Expression* expression = node->expression(); | 1163 Expression* expression = node->expression(); |
| 1093 expression->MarkAsStatement(); | 1164 expression->MarkAsStatement(); |
| 1094 Load(expression); | 1165 Load(expression); |
| 1095 __ pop(); | 1166 frame_->Pop(); |
| 1096 } | 1167 } |
| 1097 | 1168 |
| 1098 | 1169 |
| 1099 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1170 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1100 Comment cmnt(masm_, "// EmptyStatement"); | 1171 Comment cmnt(masm_, "// EmptyStatement"); |
| 1101 // nothing to do | 1172 // nothing to do |
| 1102 } | 1173 } |
| 1103 | 1174 |
| 1104 | 1175 |
| 1105 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1176 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 Visit(node->else_statement()); | 1221 Visit(node->else_statement()); |
| 1151 | 1222 |
| 1152 } else { | 1223 } else { |
| 1153 Comment cmnt(masm_, "[ If"); | 1224 Comment cmnt(masm_, "[ If"); |
| 1154 ASSERT(!has_then_stm && !has_else_stm); | 1225 ASSERT(!has_then_stm && !has_else_stm); |
| 1155 // if (cond) | 1226 // if (cond) |
| 1156 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1227 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
| 1157 if (has_cc()) { | 1228 if (has_cc()) { |
| 1158 cc_reg_ = al; | 1229 cc_reg_ = al; |
| 1159 } else { | 1230 } else { |
| 1160 __ pop(r0); // __ Pop(no_reg) | 1231 frame_->Pop(); |
| 1161 } | 1232 } |
| 1162 } | 1233 } |
| 1163 | 1234 |
| 1164 // end | 1235 // end |
| 1165 __ bind(&exit); | 1236 __ bind(&exit); |
| 1166 } | 1237 } |
| 1167 | 1238 |
| 1168 | 1239 |
| 1169 void CodeGenerator::CleanStack(int num_bytes) { | 1240 void CodeGenerator::CleanStack(int num_bytes) { |
| 1170 ASSERT(num_bytes >= 0); | 1241 ASSERT(num_bytes % kPointerSize == 0); |
| 1171 if (num_bytes > 0) { | 1242 frame_->Drop(num_bytes / kPointerSize); |
| 1172 __ add(sp, sp, Operand(num_bytes)); | |
| 1173 } | |
| 1174 } | 1243 } |
| 1175 | 1244 |
| 1176 | 1245 |
| 1177 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1246 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1178 Comment cmnt(masm_, "[ ContinueStatement"); | 1247 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1179 if (FLAG_debug_info) RecordStatementPosition(node); | 1248 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1180 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1249 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1181 __ b(node->target()->continue_target()); | 1250 __ b(node->target()->continue_target()); |
| 1182 } | 1251 } |
| 1183 | 1252 |
| 1184 | 1253 |
| 1185 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1254 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1186 Comment cmnt(masm_, "[ BreakStatement"); | 1255 Comment cmnt(masm_, "[ BreakStatement"); |
| 1187 if (FLAG_debug_info) RecordStatementPosition(node); | 1256 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1188 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1257 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1189 __ b(node->target()->break_target()); | 1258 __ b(node->target()->break_target()); |
| 1190 } | 1259 } |
| 1191 | 1260 |
| 1192 | 1261 |
| 1193 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1262 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1194 Comment cmnt(masm_, "[ ReturnStatement"); | 1263 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1195 if (FLAG_debug_info) RecordStatementPosition(node); | 1264 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1196 Load(node->expression()); | 1265 Load(node->expression()); |
| 1197 // Move the function result into r0. | 1266 // Move the function result into r0. |
| 1198 __ pop(r0); | 1267 frame_->Pop(r0); |
| 1199 | 1268 |
| 1200 __ b(&function_return_); | 1269 __ b(&function_return_); |
| 1201 } | 1270 } |
| 1202 | 1271 |
| 1203 | 1272 |
| 1204 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1273 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1205 Comment cmnt(masm_, "[ WithEnterStatement"); | 1274 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1206 if (FLAG_debug_info) RecordStatementPosition(node); | 1275 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1207 Load(node->expression()); | 1276 Load(node->expression()); |
| 1208 __ CallRuntime(Runtime::kPushContext, 1); | 1277 __ CallRuntime(Runtime::kPushContext, 1); |
| 1209 if (kDebug) { | 1278 if (kDebug) { |
| 1210 Label verified_true; | 1279 Label verified_true; |
| 1211 __ cmp(r0, Operand(cp)); | 1280 __ cmp(r0, Operand(cp)); |
| 1212 __ b(eq, &verified_true); | 1281 __ b(eq, &verified_true); |
| 1213 __ stop("PushContext: r0 is expected to be the same as cp"); | 1282 __ stop("PushContext: r0 is expected to be the same as cp"); |
| 1214 __ bind(&verified_true); | 1283 __ bind(&verified_true); |
| 1215 } | 1284 } |
| 1216 // Update context local. | 1285 // Update context local. |
| 1217 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1286 __ str(cp, frame_->Context()); |
| 1218 } | 1287 } |
| 1219 | 1288 |
| 1220 | 1289 |
| 1221 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1290 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1222 Comment cmnt(masm_, "[ WithExitStatement"); | 1291 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1223 // Pop context. | 1292 // Pop context. |
| 1224 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); | 1293 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); |
| 1225 // Update context local. | 1294 // Update context local. |
| 1226 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1295 __ str(cp, frame_->Context()); |
| 1227 } | 1296 } |
| 1228 | 1297 |
| 1229 | 1298 |
| 1230 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1299 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| 1231 return kFastSwitchMaxOverheadFactor; | 1300 return kFastSwitchMaxOverheadFactor; |
| 1232 } | 1301 } |
| 1233 | 1302 |
| 1234 int CodeGenerator::FastCaseSwitchMinCaseCount() { | 1303 int CodeGenerator::FastCaseSwitchMinCaseCount() { |
| 1235 return kFastSwitchMinCaseCount; | 1304 return kFastSwitchMinCaseCount; |
| 1236 } | 1305 } |
| 1237 | 1306 |
| 1238 | 1307 |
| 1239 void CodeGenerator::GenerateFastCaseSwitchJumpTable( | 1308 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
| 1240 SwitchStatement* node, | 1309 SwitchStatement* node, |
| 1241 int min_index, | 1310 int min_index, |
| 1242 int range, | 1311 int range, |
| 1243 Label* fail_label, | 1312 Label* fail_label, |
| 1244 Vector<Label*> case_targets, | 1313 Vector<Label*> case_targets, |
| 1245 Vector<Label> case_labels) { | 1314 Vector<Label> case_labels) { |
| 1246 | 1315 |
| 1247 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); | 1316 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); |
| 1248 | 1317 |
| 1249 __ pop(r0); | 1318 frame_->Pop(r0); |
| 1250 | 1319 |
| 1251 // Test for a Smi value in a HeapNumber. | 1320 // Test for a Smi value in a HeapNumber. |
| 1252 Label is_smi; | 1321 Label is_smi; |
| 1253 __ tst(r0, Operand(kSmiTagMask)); | 1322 __ tst(r0, Operand(kSmiTagMask)); |
| 1254 __ b(eq, &is_smi); | 1323 __ b(eq, &is_smi); |
| 1255 __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag)); | 1324 __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag)); |
| 1256 __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag)); | 1325 __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag)); |
| 1257 __ cmp(r1, Operand(HEAP_NUMBER_TYPE)); | 1326 __ cmp(r1, Operand(HEAP_NUMBER_TYPE)); |
| 1258 __ b(ne, fail_label); | 1327 __ b(ne, fail_label); |
| 1259 __ push(r0); | 1328 frame_->Push(r0); |
| 1260 __ CallRuntime(Runtime::kNumberToSmi, 1); | 1329 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| 1261 __ bind(&is_smi); | 1330 __ bind(&is_smi); |
| 1262 | 1331 |
| 1263 if (min_index != 0) { | 1332 if (min_index != 0) { |
| 1264 // Small positive numbers can be immediate operands. | 1333 // Small positive numbers can be immediate operands. |
| 1265 if (min_index < 0) { | 1334 if (min_index < 0) { |
| 1266 // If min_index is Smi::kMinValue, -min_index is not a Smi. | 1335 // If min_index is Smi::kMinValue, -min_index is not a Smi. |
| 1267 if (Smi::IsValid(-min_index)) { | 1336 if (Smi::IsValid(-min_index)) { |
| 1268 __ add(r0, r0, Operand(Smi::FromInt(-min_index))); | 1337 __ add(r0, r0, Operand(Smi::FromInt(-min_index))); |
| 1269 } else { | 1338 } else { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1317 // statements if it does not match any of the cases. | 1386 // statements if it does not match any of the cases. |
| 1318 __ b(&next); | 1387 __ b(&next); |
| 1319 | 1388 |
| 1320 // Bind the default case label, so we can branch to it when we | 1389 // Bind the default case label, so we can branch to it when we |
| 1321 // have compared against all other cases. | 1390 // have compared against all other cases. |
| 1322 ASSERT(default_case.is_unused()); // at most one default clause | 1391 ASSERT(default_case.is_unused()); // at most one default clause |
| 1323 __ bind(&default_case); | 1392 __ bind(&default_case); |
| 1324 } else { | 1393 } else { |
| 1325 __ bind(&next); | 1394 __ bind(&next); |
| 1326 next.Unuse(); | 1395 next.Unuse(); |
| 1327 __ ldr(r0, MemOperand(sp, 0)); | 1396 __ ldr(r0, frame_->Top()); |
| 1328 __ push(r0); // duplicate TOS | 1397 frame_->Push(r0); // duplicate TOS |
| 1329 Load(clause->label()); | 1398 Load(clause->label()); |
| 1330 Comparison(eq, true); | 1399 Comparison(eq, true); |
| 1331 Branch(false, &next); | 1400 Branch(false, &next); |
| 1332 } | 1401 } |
| 1333 | 1402 |
| 1334 // Entering the case statement for the first time. Remove the switch value | 1403 // Entering the case statement for the first time. Remove the switch value |
| 1335 // from the stack. | 1404 // from the stack. |
| 1336 __ pop(r0); | 1405 frame_->Pop(); |
| 1337 | 1406 |
| 1338 // Generate code for the body. | 1407 // Generate code for the body. |
| 1339 // This is also the target for the fall through from the previous case's | 1408 // This is also the target for the fall through from the previous case's |
| 1340 // statements which has to skip over the matching code and the popping of | 1409 // statements which has to skip over the matching code and the popping of |
| 1341 // the switch value. | 1410 // the switch value. |
| 1342 __ bind(&fall_through); | 1411 __ bind(&fall_through); |
| 1343 fall_through.Unuse(); | 1412 fall_through.Unuse(); |
| 1344 VisitStatements(clause->statements()); | 1413 VisitStatements(clause->statements()); |
| 1345 __ b(&fall_through); | 1414 __ b(&fall_through); |
| 1346 } | 1415 } |
| 1347 | 1416 |
| 1348 __ bind(&next); | 1417 __ bind(&next); |
| 1349 // Reached the end of the case statements without matching any of the cases. | 1418 // Reached the end of the case statements without matching any of the cases. |
| 1350 if (default_case.is_bound()) { | 1419 if (default_case.is_bound()) { |
| 1351 // A default case exists -> execute its statements. | 1420 // A default case exists -> execute its statements. |
| 1352 __ b(&default_case); | 1421 __ b(&default_case); |
| 1353 } else { | 1422 } else { |
| 1354 // Remove the switch value from the stack. | 1423 // Remove the switch value from the stack. |
| 1355 __ pop(r0); | 1424 frame_->Pop(); |
| 1356 } | 1425 } |
| 1357 | 1426 |
| 1358 __ bind(&fall_through); | 1427 __ bind(&fall_through); |
| 1359 __ bind(node->break_target()); | 1428 __ bind(node->break_target()); |
| 1360 } | 1429 } |
| 1361 | 1430 |
| 1362 | 1431 |
| 1363 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1432 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1364 Comment cmnt(masm_, "[ LoopStatement"); | 1433 Comment cmnt(masm_, "[ LoopStatement"); |
| 1365 if (FLAG_debug_info) RecordStatementPosition(node); | 1434 if (FLAG_debug_info) RecordStatementPosition(node); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1441 // can restore the stack. | 1510 // can restore the stack. |
| 1442 const int kForInStackSize = 5 * kPointerSize; | 1511 const int kForInStackSize = 5 * kPointerSize; |
| 1443 break_stack_height_ += kForInStackSize; | 1512 break_stack_height_ += kForInStackSize; |
| 1444 node->set_break_stack_height(break_stack_height_); | 1513 node->set_break_stack_height(break_stack_height_); |
| 1445 | 1514 |
| 1446 Label loop, next, entry, cleanup, exit, primitive, jsobject; | 1515 Label loop, next, entry, cleanup, exit, primitive, jsobject; |
| 1447 Label filter_key, end_del_check, fixed_array, non_string; | 1516 Label filter_key, end_del_check, fixed_array, non_string; |
| 1448 | 1517 |
| 1449 // Get the object to enumerate over (converted to JSObject). | 1518 // Get the object to enumerate over (converted to JSObject). |
| 1450 Load(node->enumerable()); | 1519 Load(node->enumerable()); |
| 1451 __ pop(r0); | 1520 frame_->Pop(r0); |
| 1452 | 1521 |
| 1453 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1522 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 1454 // to the specification. 12.6.4 mandates a call to ToObject. | 1523 // to the specification. 12.6.4 mandates a call to ToObject. |
| 1455 __ cmp(r0, Operand(Factory::undefined_value())); | 1524 __ cmp(r0, Operand(Factory::undefined_value())); |
| 1456 __ b(eq, &exit); | 1525 __ b(eq, &exit); |
| 1457 __ cmp(r0, Operand(Factory::null_value())); | 1526 __ cmp(r0, Operand(Factory::null_value())); |
| 1458 __ b(eq, &exit); | 1527 __ b(eq, &exit); |
| 1459 | 1528 |
| 1460 // Stack layout in body: | 1529 // Stack layout in body: |
| 1461 // [iteration counter (Smi)] | 1530 // [iteration counter (Smi)] |
| 1462 // [length of array] | 1531 // [length of array] |
| 1463 // [FixedArray] | 1532 // [FixedArray] |
| 1464 // [Map or 0] | 1533 // [Map or 0] |
| 1465 // [Object] | 1534 // [Object] |
| 1466 | 1535 |
| 1467 // Check if enumerable is already a JSObject | 1536 // Check if enumerable is already a JSObject |
| 1468 __ tst(r0, Operand(kSmiTagMask)); | 1537 __ tst(r0, Operand(kSmiTagMask)); |
| 1469 __ b(eq, &primitive); | 1538 __ b(eq, &primitive); |
| 1470 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 1539 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 1471 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 1540 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 1472 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | 1541 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); |
| 1473 __ b(hs, &jsobject); | 1542 __ b(hs, &jsobject); |
| 1474 | 1543 |
| 1475 __ bind(&primitive); | 1544 __ bind(&primitive); |
| 1476 __ push(r0); | 1545 frame_->Push(r0); |
| 1477 __ mov(r0, Operand(0)); | 1546 __ mov(r0, Operand(0)); |
| 1478 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); | 1547 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); |
| 1479 | 1548 |
| 1480 | 1549 |
| 1481 __ bind(&jsobject); | 1550 __ bind(&jsobject); |
| 1482 | 1551 |
| 1483 // Get the set of properties (as a FixedArray or Map). | 1552 // Get the set of properties (as a FixedArray or Map). |
| 1484 __ push(r0); // duplicate the object being enumerated | 1553 frame_->Push(r0); // duplicate the object being enumerated |
| 1485 __ push(r0); | 1554 frame_->Push(r0); |
| 1486 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 1555 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 1487 | 1556 |
| 1488 // If we got a Map, we can do a fast modification check. | 1557 // If we got a Map, we can do a fast modification check. |
| 1489 // Otherwise, we got a FixedArray, and we have to do a slow check. | 1558 // Otherwise, we got a FixedArray, and we have to do a slow check. |
| 1490 __ mov(r2, Operand(r0)); | 1559 __ mov(r2, Operand(r0)); |
| 1491 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); | 1560 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); |
| 1492 __ cmp(r1, Operand(Factory::meta_map())); | 1561 __ cmp(r1, Operand(Factory::meta_map())); |
| 1493 __ b(ne, &fixed_array); | 1562 __ b(ne, &fixed_array); |
| 1494 | 1563 |
| 1495 // Get enum cache | 1564 // Get enum cache |
| 1496 __ mov(r1, Operand(r0)); | 1565 __ mov(r1, Operand(r0)); |
| 1497 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset)); | 1566 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset)); |
| 1498 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); | 1567 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); |
| 1499 __ ldr(r2, | 1568 __ ldr(r2, |
| 1500 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 1569 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 1501 | 1570 |
| 1502 __ push(r0); // map | 1571 frame_->Push(r0); // map |
| 1503 __ push(r2); // enum cache bridge cache | 1572 frame_->Push(r2); // enum cache bridge cache |
| 1504 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset)); | 1573 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset)); |
| 1505 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | 1574 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 1506 __ push(r0); | 1575 frame_->Push(r0); |
| 1507 __ mov(r0, Operand(Smi::FromInt(0))); | 1576 __ mov(r0, Operand(Smi::FromInt(0))); |
| 1508 __ push(r0); | 1577 frame_->Push(r0); |
| 1509 __ b(&entry); | 1578 __ b(&entry); |
| 1510 | 1579 |
| 1511 | 1580 |
| 1512 __ bind(&fixed_array); | 1581 __ bind(&fixed_array); |
| 1513 | 1582 |
| 1514 __ mov(r1, Operand(Smi::FromInt(0))); | 1583 __ mov(r1, Operand(Smi::FromInt(0))); |
| 1515 __ push(r1); // insert 0 in place of Map | 1584 frame_->Push(r1); // insert 0 in place of Map |
| 1516 __ push(r0); | 1585 frame_->Push(r0); |
| 1517 | 1586 |
| 1518 // Push the length of the array and the initial index onto the stack. | 1587 // Push the length of the array and the initial index onto the stack. |
| 1519 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset)); | 1588 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset)); |
| 1520 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | 1589 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 1521 __ push(r0); | 1590 frame_->Push(r0); |
| 1522 __ mov(r0, Operand(Smi::FromInt(0))); // init index | 1591 __ mov(r0, Operand(Smi::FromInt(0))); // init index |
| 1523 __ push(r0); | 1592 frame_->Push(r0); |
| 1524 | 1593 |
| 1525 __ b(&entry); | 1594 __ b(&entry); |
| 1526 | 1595 |
| 1527 // Body. | 1596 // Body. |
| 1528 __ bind(&loop); | 1597 __ bind(&loop); |
| 1529 Visit(node->body()); | 1598 Visit(node->body()); |
| 1530 | 1599 |
| 1531 // Next. | 1600 // Next. |
| 1532 __ bind(node->continue_target()); | 1601 __ bind(node->continue_target()); |
| 1533 __ bind(&next); | 1602 __ bind(&next); |
| 1534 __ pop(r0); | 1603 frame_->Pop(r0); |
| 1535 __ add(r0, r0, Operand(Smi::FromInt(1))); | 1604 __ add(r0, r0, Operand(Smi::FromInt(1))); |
| 1536 __ push(r0); | 1605 frame_->Push(r0); |
| 1537 | 1606 |
| 1538 // Condition. | 1607 // Condition. |
| 1539 __ bind(&entry); | 1608 __ bind(&entry); |
| 1540 | 1609 |
| 1541 // sp[0] : index | 1610 // sp[0] : index |
| 1542 // sp[1] : array/enum cache length | 1611 // sp[1] : array/enum cache length |
| 1543 // sp[2] : array or enum cache | 1612 // sp[2] : array or enum cache |
| 1544 // sp[3] : 0 or map | 1613 // sp[3] : 0 or map |
| 1545 // sp[4] : enumerable | 1614 // sp[4] : enumerable |
| 1546 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); // load the current count | 1615 __ ldr(r0, frame_->Element(0)); // load the current count |
| 1547 __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // load the length | 1616 __ ldr(r1, frame_->Element(1)); // load the length |
| 1548 __ cmp(r0, Operand(r1)); // compare to the array length | 1617 __ cmp(r0, Operand(r1)); // compare to the array length |
| 1549 __ b(hs, &cleanup); | 1618 __ b(hs, &cleanup); |
| 1550 | 1619 |
| 1551 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); | 1620 __ ldr(r0, frame_->Element(0)); |
| 1552 | 1621 |
| 1553 // Get the i'th entry of the array. | 1622 // Get the i'th entry of the array. |
| 1554 __ ldr(r2, MemOperand(sp, 2 * kPointerSize)); | 1623 __ ldr(r2, frame_->Element(2)); |
| 1555 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 1624 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 1556 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); | 1625 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 1557 | 1626 |
| 1558 // Get Map or 0. | 1627 // Get Map or 0. |
| 1559 __ ldr(r2, MemOperand(sp, 3 * kPointerSize)); | 1628 __ ldr(r2, frame_->Element(3)); |
| 1560 // Check if this (still) matches the map of the enumerable. | 1629 // Check if this (still) matches the map of the enumerable. |
| 1561 // If not, we have to filter the key. | 1630 // If not, we have to filter the key. |
| 1562 __ ldr(r1, MemOperand(sp, 4 * kPointerSize)); | 1631 __ ldr(r1, frame_->Element(4)); |
| 1563 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 1632 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1564 __ cmp(r1, Operand(r2)); | 1633 __ cmp(r1, Operand(r2)); |
| 1565 __ b(eq, &end_del_check); | 1634 __ b(eq, &end_del_check); |
| 1566 | 1635 |
| 1567 // Convert the entry to a string (or null if it isn't a property anymore). | 1636 // Convert the entry to a string (or null if it isn't a property anymore). |
| 1568 __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable | 1637 __ ldr(r0, frame_->Element(4)); // push enumerable |
| 1569 __ push(r0); | 1638 frame_->Push(r0); |
| 1570 __ push(r3); // push entry | 1639 frame_->Push(r3); // push entry |
| 1571 __ mov(r0, Operand(1)); | 1640 __ mov(r0, Operand(1)); |
| 1572 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS); | 1641 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS); |
| 1573 __ mov(r3, Operand(r0)); | 1642 __ mov(r3, Operand(r0)); |
| 1574 | 1643 |
| 1575 // If the property has been removed while iterating, we just skip it. | 1644 // If the property has been removed while iterating, we just skip it. |
| 1576 __ cmp(r3, Operand(Factory::null_value())); | 1645 __ cmp(r3, Operand(Factory::null_value())); |
| 1577 __ b(eq, &next); | 1646 __ b(eq, &next); |
| 1578 | 1647 |
| 1579 | 1648 |
| 1580 __ bind(&end_del_check); | 1649 __ bind(&end_del_check); |
| 1581 | 1650 |
| 1582 // Store the entry in the 'each' expression and take another spin in the loop. | 1651 // Store the entry in the 'each' expression and take another spin in the loop. |
| 1583 // r3: i'th entry of the enum cache (or string there of) | 1652 // r3: i'th entry of the enum cache (or string there of) |
| 1584 __ push(r3); // push entry | 1653 frame_->Push(r3); // push entry |
| 1585 { Reference each(this, node->each()); | 1654 { Reference each(this, node->each()); |
| 1586 if (!each.is_illegal()) { | 1655 if (!each.is_illegal()) { |
| 1587 if (each.size() > 0) { | 1656 if (each.size() > 0) { |
| 1588 __ ldr(r0, MemOperand(sp, kPointerSize * each.size())); | 1657 __ ldr(r0, frame_->Element(each.size())); |
| 1589 __ push(r0); | 1658 frame_->Push(r0); |
| 1590 } | 1659 } |
| 1591 // If the reference was to a slot we rely on the convenient property | 1660 // If the reference was to a slot we rely on the convenient property |
| 1592 // that it doesn't matter whether a value (eg, r3 pushed above) is | 1661 // that it doesn't matter whether a value (eg, r3 pushed above) is |
| 1593 // right on top of or right underneath a zero-sized reference. | 1662 // right on top of or right underneath a zero-sized reference. |
| 1594 each.SetValue(NOT_CONST_INIT); | 1663 each.SetValue(NOT_CONST_INIT); |
| 1595 if (each.size() > 0) { | 1664 if (each.size() > 0) { |
| 1596 // It's safe to pop the value lying on top of the reference before | 1665 // It's safe to pop the value lying on top of the reference before |
| 1597 // unloading the reference itself (which preserves the top of stack, | 1666 // unloading the reference itself (which preserves the top of stack, |
| 1598 // ie, now the topmost value of the non-zero sized reference), since | 1667 // ie, now the topmost value of the non-zero sized reference), since |
| 1599 // we will discard the top of stack after unloading the reference | 1668 // we will discard the top of stack after unloading the reference |
| 1600 // anyway. | 1669 // anyway. |
| 1601 __ pop(r0); | 1670 frame_->Pop(r0); |
| 1602 } | 1671 } |
| 1603 } | 1672 } |
| 1604 } | 1673 } |
| 1605 // Discard the i'th entry pushed above or else the remainder of the | 1674 // Discard the i'th entry pushed above or else the remainder of the |
| 1606 // reference, whichever is currently on top of the stack. | 1675 // reference, whichever is currently on top of the stack. |
| 1607 __ pop(); | 1676 frame_->Pop(); |
| 1608 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1677 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1609 __ jmp(&loop); | 1678 __ jmp(&loop); |
| 1610 | 1679 |
| 1611 // Cleanup. | 1680 // Cleanup. |
| 1612 __ bind(&cleanup); | 1681 __ bind(&cleanup); |
| 1613 __ bind(node->break_target()); | 1682 __ bind(node->break_target()); |
| 1614 __ add(sp, sp, Operand(5 * kPointerSize)); | 1683 frame_->Drop(5); |
| 1615 | 1684 |
| 1616 // Exit. | 1685 // Exit. |
| 1617 __ bind(&exit); | 1686 __ bind(&exit); |
| 1618 | 1687 |
| 1619 break_stack_height_ -= kForInStackSize; | 1688 break_stack_height_ -= kForInStackSize; |
| 1620 } | 1689 } |
| 1621 | 1690 |
| 1622 | 1691 |
| 1623 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 1692 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 1624 Comment cmnt(masm_, "[ TryCatch"); | 1693 Comment cmnt(masm_, "[ TryCatch"); |
| 1625 | 1694 |
| 1626 Label try_block, exit; | 1695 Label try_block, exit; |
| 1627 | 1696 |
| 1628 __ bl(&try_block); | 1697 __ bl(&try_block); |
| 1629 | |
| 1630 // --- Catch block --- | 1698 // --- Catch block --- |
| 1699 frame_->Push(r0); |
| 1631 | 1700 |
| 1632 // Store the caught exception in the catch variable. | 1701 // Store the caught exception in the catch variable. |
| 1633 __ push(r0); | |
| 1634 { Reference ref(this, node->catch_var()); | 1702 { Reference ref(this, node->catch_var()); |
| 1635 ASSERT(ref.is_slot()); | 1703 ASSERT(ref.is_slot()); |
| 1636 // Here we make use of the convenient property that it doesn't matter | 1704 // Here we make use of the convenient property that it doesn't matter |
| 1637 // whether a value is immediately on top of or underneath a zero-sized | 1705 // whether a value is immediately on top of or underneath a zero-sized |
| 1638 // reference. | 1706 // reference. |
| 1639 ref.SetValue(NOT_CONST_INIT); | 1707 ref.SetValue(NOT_CONST_INIT); |
| 1640 } | 1708 } |
| 1641 | 1709 |
| 1642 // Remove the exception from the stack. | 1710 // Remove the exception from the stack. |
| 1643 __ pop(); | 1711 frame_->Pop(); |
| 1644 | 1712 |
| 1645 VisitStatements(node->catch_block()->statements()); | 1713 VisitStatements(node->catch_block()->statements()); |
| 1646 __ b(&exit); | 1714 __ b(&exit); |
| 1647 | 1715 |
| 1648 | 1716 |
| 1649 // --- Try block --- | 1717 // --- Try block --- |
| 1650 __ bind(&try_block); | 1718 __ bind(&try_block); |
| 1651 | 1719 |
| 1652 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); | 1720 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); |
| 1653 | 1721 |
| 1654 // Shadow the labels for all escapes from the try block, including | 1722 // Shadow the labels for all escapes from the try block, including |
| 1655 // returns. During shadowing, the original label is hidden as the | 1723 // returns. During shadowing, the original label is hidden as the |
| 1656 // LabelShadow and operations on the original actually affect the | 1724 // LabelShadow and operations on the original actually affect the |
| 1657 // shadowing label. | 1725 // shadowing label. |
| 1658 // | 1726 // |
| 1659 // We should probably try to unify the escaping labels and the return | 1727 // We should probably try to unify the escaping labels and the return |
| 1660 // label. | 1728 // label. |
| 1661 int nof_escapes = node->escaping_labels()->length(); | 1729 int nof_escapes = node->escaping_labels()->length(); |
| 1662 List<LabelShadow*> shadows(1 + nof_escapes); | 1730 List<LabelShadow*> shadows(1 + nof_escapes); |
| 1663 shadows.Add(new LabelShadow(&function_return_)); | 1731 shadows.Add(new LabelShadow(&function_return_)); |
| 1664 for (int i = 0; i < nof_escapes; i++) { | 1732 for (int i = 0; i < nof_escapes; i++) { |
| 1665 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); | 1733 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); |
| 1666 } | 1734 } |
| 1667 | 1735 |
| 1668 // Generate code for the statements in the try block. | 1736 // Generate code for the statements in the try block. |
| 1669 VisitStatements(node->try_block()->statements()); | 1737 VisitStatements(node->try_block()->statements()); |
| 1670 __ pop(r0); // Discard the result. | 1738 frame_->Pop(); // Discard the result. |
| 1671 | 1739 |
| 1672 // Stop the introduced shadowing and count the number of required unlinks. | 1740 // Stop the introduced shadowing and count the number of required unlinks. |
| 1673 // After shadowing stops, the original labels are unshadowed and the | 1741 // After shadowing stops, the original labels are unshadowed and the |
| 1674 // LabelShadows represent the formerly shadowing labels. | 1742 // LabelShadows represent the formerly shadowing labels. |
| 1675 int nof_unlinks = 0; | 1743 int nof_unlinks = 0; |
| 1676 for (int i = 0; i <= nof_escapes; i++) { | 1744 for (int i = 0; i <= nof_escapes; i++) { |
| 1677 shadows[i]->StopShadowing(); | 1745 shadows[i]->StopShadowing(); |
| 1678 if (shadows[i]->is_linked()) nof_unlinks++; | 1746 if (shadows[i]->is_linked()) nof_unlinks++; |
| 1679 } | 1747 } |
| 1680 | 1748 |
| 1681 // Unlink from try chain. | 1749 // Unlink from try chain. |
| 1682 // TOS contains code slot | 1750 // TOS contains code slot |
| 1683 const int kNextOffset = StackHandlerConstants::kNextOffset + | 1751 const int kNextIndex = (StackHandlerConstants::kNextOffset |
| 1684 StackHandlerConstants::kAddressDisplacement; | 1752 + StackHandlerConstants::kAddressDisplacement) |
| 1685 __ ldr(r1, MemOperand(sp, kNextOffset)); // read next_sp | 1753 / kPointerSize; |
| 1754 __ ldr(r1, frame_->Element(kNextIndex)); // read next_sp |
| 1686 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 1755 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 1687 __ str(r1, MemOperand(r3)); | 1756 __ str(r1, MemOperand(r3)); |
| 1688 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | 1757 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| 1689 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); | 1758 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 1690 // Code slot popped. | 1759 // Code slot popped. |
| 1691 if (nof_unlinks > 0) __ b(&exit); | 1760 if (nof_unlinks > 0) __ b(&exit); |
| 1692 | 1761 |
| 1693 // Generate unlink code for the (formerly) shadowing labels that have been | 1762 // Generate unlink code for the (formerly) shadowing labels that have been |
| 1694 // jumped to. | 1763 // jumped to. |
| 1695 for (int i = 0; i <= nof_escapes; i++) { | 1764 for (int i = 0; i <= nof_escapes; i++) { |
| 1696 if (shadows[i]->is_linked()) { | 1765 if (shadows[i]->is_linked()) { |
| 1697 // Unlink from try chain; | 1766 // Unlink from try chain; |
| 1698 __ bind(shadows[i]); | 1767 __ bind(shadows[i]); |
| 1699 | 1768 |
| 1700 // Reload sp from the top handler, because some statements that we | 1769 // Reload sp from the top handler, because some statements that we |
| 1701 // break from (eg, for...in) may have left stuff on the stack. | 1770 // break from (eg, for...in) may have left stuff on the stack. |
| 1702 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 1771 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 1703 __ ldr(sp, MemOperand(r3)); | 1772 __ ldr(sp, MemOperand(r3)); |
| 1704 | 1773 |
| 1705 __ ldr(r1, MemOperand(sp, kNextOffset)); | 1774 __ ldr(r1, frame_->Element(kNextIndex)); |
| 1706 __ str(r1, MemOperand(r3)); | 1775 __ str(r1, MemOperand(r3)); |
| 1707 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | 1776 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| 1708 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); | 1777 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 1709 // Code slot popped. | 1778 // Code slot popped. |
| 1710 | 1779 |
| 1711 __ b(shadows[i]->original_label()); | 1780 __ b(shadows[i]->original_label()); |
| 1712 } | 1781 } |
| 1713 } | 1782 } |
| 1714 | 1783 |
| 1715 __ bind(&exit); | 1784 __ bind(&exit); |
| 1716 } | 1785 } |
| 1717 | 1786 |
| 1718 | 1787 |
| 1719 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 1788 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 1720 Comment cmnt(masm_, "[ TryFinally"); | 1789 Comment cmnt(masm_, "[ TryFinally"); |
| 1721 | 1790 |
| 1722 // State: Used to keep track of reason for entering the finally | 1791 // State: Used to keep track of reason for entering the finally |
| 1723 // block. Should probably be extended to hold information for | 1792 // block. Should probably be extended to hold information for |
| 1724 // break/continue from within the try block. | 1793 // break/continue from within the try block. |
| 1725 enum { FALLING, THROWING, JUMPING }; | 1794 enum { FALLING, THROWING, JUMPING }; |
| 1726 | 1795 |
| 1727 Label exit, unlink, try_block, finally_block; | 1796 Label exit, unlink, try_block, finally_block; |
| 1728 | 1797 |
| 1729 __ bl(&try_block); | 1798 __ bl(&try_block); |
| 1730 | 1799 |
| 1731 __ push(r0); // save exception object on the stack | 1800 frame_->Push(r0); // save exception object on the stack |
| 1732 // In case of thrown exceptions, this is where we continue. | 1801 // In case of thrown exceptions, this is where we continue. |
| 1733 __ mov(r2, Operand(Smi::FromInt(THROWING))); | 1802 __ mov(r2, Operand(Smi::FromInt(THROWING))); |
| 1734 __ b(&finally_block); | 1803 __ b(&finally_block); |
| 1735 | 1804 |
| 1736 | 1805 |
| 1737 // --- Try block --- | 1806 // --- Try block --- |
| 1738 __ bind(&try_block); | 1807 __ bind(&try_block); |
| 1739 | 1808 |
| 1740 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); | 1809 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); |
| 1741 | 1810 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1759 // After shadowing stops, the original labels are unshadowed and the | 1828 // After shadowing stops, the original labels are unshadowed and the |
| 1760 // LabelShadows represent the formerly shadowing labels. | 1829 // LabelShadows represent the formerly shadowing labels. |
| 1761 int nof_unlinks = 0; | 1830 int nof_unlinks = 0; |
| 1762 for (int i = 0; i <= nof_escapes; i++) { | 1831 for (int i = 0; i <= nof_escapes; i++) { |
| 1763 shadows[i]->StopShadowing(); | 1832 shadows[i]->StopShadowing(); |
| 1764 if (shadows[i]->is_linked()) nof_unlinks++; | 1833 if (shadows[i]->is_linked()) nof_unlinks++; |
| 1765 } | 1834 } |
| 1766 | 1835 |
| 1767 // Set the state on the stack to FALLING. | 1836 // Set the state on the stack to FALLING. |
| 1768 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS | 1837 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS |
| 1769 __ push(r0); | 1838 frame_->Push(r0); |
| 1770 __ mov(r2, Operand(Smi::FromInt(FALLING))); | 1839 __ mov(r2, Operand(Smi::FromInt(FALLING))); |
| 1771 if (nof_unlinks > 0) __ b(&unlink); | 1840 if (nof_unlinks > 0) __ b(&unlink); |
| 1772 | 1841 |
| 1773 // Generate code to set the state for the (formerly) shadowing labels that | 1842 // Generate code to set the state for the (formerly) shadowing labels that |
| 1774 // have been jumped to. | 1843 // have been jumped to. |
| 1775 for (int i = 0; i <= nof_escapes; i++) { | 1844 for (int i = 0; i <= nof_escapes; i++) { |
| 1776 if (shadows[i]->is_linked()) { | 1845 if (shadows[i]->is_linked()) { |
| 1777 __ bind(shadows[i]); | 1846 __ bind(shadows[i]); |
| 1778 if (shadows[i]->original_label() == &function_return_) { | 1847 if (shadows[i]->original_label() == &function_return_) { |
| 1779 // If this label shadowed the function return, materialize the | 1848 // If this label shadowed the function return, materialize the |
| 1780 // return value on the stack. | 1849 // return value on the stack. |
| 1781 __ push(r0); | 1850 frame_->Push(r0); |
| 1782 } else { | 1851 } else { |
| 1783 // Fake TOS for labels that shadowed breaks and continues. | 1852 // Fake TOS for labels that shadowed breaks and continues. |
| 1784 __ mov(r0, Operand(Factory::undefined_value())); | 1853 __ mov(r0, Operand(Factory::undefined_value())); |
| 1785 __ push(r0); | 1854 frame_->Push(r0); |
| 1786 } | 1855 } |
| 1787 __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); | 1856 __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); |
| 1788 __ b(&unlink); | 1857 __ b(&unlink); |
| 1789 } | 1858 } |
| 1790 } | 1859 } |
| 1791 | 1860 |
| 1792 // Unlink from try chain; | 1861 // Unlink from try chain; |
| 1793 __ bind(&unlink); | 1862 __ bind(&unlink); |
| 1794 | 1863 |
| 1795 __ pop(r0); // Store TOS in r0 across stack manipulation | 1864 frame_->Pop(r0); // Store TOS in r0 across stack manipulation |
| 1796 // Reload sp from the top handler, because some statements that we | 1865 // Reload sp from the top handler, because some statements that we |
| 1797 // break from (eg, for...in) may have left stuff on the stack. | 1866 // break from (eg, for...in) may have left stuff on the stack. |
| 1798 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 1867 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 1799 __ ldr(sp, MemOperand(r3)); | 1868 __ ldr(sp, MemOperand(r3)); |
| 1800 const int kNextOffset = StackHandlerConstants::kNextOffset + | 1869 const int kNextIndex = (StackHandlerConstants::kNextOffset |
| 1801 StackHandlerConstants::kAddressDisplacement; | 1870 + StackHandlerConstants::kAddressDisplacement) |
| 1802 __ ldr(r1, MemOperand(sp, kNextOffset)); | 1871 / kPointerSize; |
| 1872 __ ldr(r1, frame_->Element(kNextIndex)); |
| 1803 __ str(r1, MemOperand(r3)); | 1873 __ str(r1, MemOperand(r3)); |
| 1804 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | 1874 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| 1805 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); | 1875 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 1806 // Code slot popped. | 1876 // Code slot popped. |
| 1807 __ push(r0); | 1877 frame_->Push(r0); |
| 1808 | 1878 |
| 1809 // --- Finally block --- | 1879 // --- Finally block --- |
| 1810 __ bind(&finally_block); | 1880 __ bind(&finally_block); |
| 1811 | 1881 |
| 1812 // Push the state on the stack. | 1882 // Push the state on the stack. |
| 1813 __ push(r2); | 1883 frame_->Push(r2); |
| 1814 | 1884 |
| 1815 // We keep two elements on the stack - the (possibly faked) result | 1885 // We keep two elements on the stack - the (possibly faked) result |
| 1816 // and the state - while evaluating the finally block. Record it, so | 1886 // and the state - while evaluating the finally block. Record it, so |
| 1817 // that a break/continue crossing this statement can restore the | 1887 // that a break/continue crossing this statement can restore the |
| 1818 // stack. | 1888 // stack. |
| 1819 const int kFinallyStackSize = 2 * kPointerSize; | 1889 const int kFinallyStackSize = 2 * kPointerSize; |
| 1820 break_stack_height_ += kFinallyStackSize; | 1890 break_stack_height_ += kFinallyStackSize; |
| 1821 | 1891 |
| 1822 // Generate code for the statements in the finally block. | 1892 // Generate code for the statements in the finally block. |
| 1823 VisitStatements(node->finally_block()->statements()); | 1893 VisitStatements(node->finally_block()->statements()); |
| 1824 | 1894 |
| 1825 // Restore state and return value or faked TOS. | 1895 // Restore state and return value or faked TOS. |
| 1826 __ pop(r2); | 1896 frame_->Pop(r2); |
| 1827 __ pop(r0); | 1897 frame_->Pop(r0); |
| 1828 break_stack_height_ -= kFinallyStackSize; | 1898 break_stack_height_ -= kFinallyStackSize; |
| 1829 | 1899 |
| 1830 // Generate code to jump to the right destination for all used (formerly) | 1900 // Generate code to jump to the right destination for all used (formerly) |
| 1831 // shadowing labels. | 1901 // shadowing labels. |
| 1832 for (int i = 0; i <= nof_escapes; i++) { | 1902 for (int i = 0; i <= nof_escapes; i++) { |
| 1833 if (shadows[i]->is_bound()) { | 1903 if (shadows[i]->is_bound()) { |
| 1834 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); | 1904 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); |
| 1835 if (shadows[i]->original_label() != &function_return_) { | 1905 if (shadows[i]->original_label() != &function_return_) { |
| 1836 Label next; | 1906 Label next; |
| 1837 __ b(ne, &next); | 1907 __ b(ne, &next); |
| 1838 __ b(shadows[i]->original_label()); | 1908 __ b(shadows[i]->original_label()); |
| 1839 __ bind(&next); | 1909 __ bind(&next); |
| 1840 } else { | 1910 } else { |
| 1841 __ b(eq, shadows[i]->original_label()); | 1911 __ b(eq, shadows[i]->original_label()); |
| 1842 } | 1912 } |
| 1843 } | 1913 } |
| 1844 } | 1914 } |
| 1845 | 1915 |
| 1846 // Check if we need to rethrow the exception. | 1916 // Check if we need to rethrow the exception. |
| 1847 __ cmp(r2, Operand(Smi::FromInt(THROWING))); | 1917 __ cmp(r2, Operand(Smi::FromInt(THROWING))); |
| 1848 __ b(ne, &exit); | 1918 __ b(ne, &exit); |
| 1849 | 1919 |
| 1850 // Rethrow exception. | 1920 // Rethrow exception. |
| 1851 __ push(r0); | 1921 frame_->Push(r0); |
| 1852 __ CallRuntime(Runtime::kReThrow, 1); | 1922 __ CallRuntime(Runtime::kReThrow, 1); |
| 1853 | 1923 |
| 1854 // Done. | 1924 // Done. |
| 1855 __ bind(&exit); | 1925 __ bind(&exit); |
| 1856 } | 1926 } |
| 1857 | 1927 |
| 1858 | 1928 |
| 1859 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 1929 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 1860 Comment cmnt(masm_, "[ DebuggerStatament"); | 1930 Comment cmnt(masm_, "[ DebuggerStatament"); |
| 1861 if (FLAG_debug_info) RecordStatementPosition(node); | 1931 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1862 __ CallRuntime(Runtime::kDebugBreak, 0); | 1932 __ CallRuntime(Runtime::kDebugBreak, 0); |
| 1863 // Ignore the return value. | 1933 // Ignore the return value. |
| 1864 } | 1934 } |
| 1865 | 1935 |
| 1866 | 1936 |
| 1867 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 1937 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 1868 ASSERT(boilerplate->IsBoilerplate()); | 1938 ASSERT(boilerplate->IsBoilerplate()); |
| 1869 | 1939 |
| 1870 // Push the boilerplate on the stack. | 1940 // Push the boilerplate on the stack. |
| 1871 __ mov(r0, Operand(boilerplate)); | 1941 __ mov(r0, Operand(boilerplate)); |
| 1872 __ push(r0); | 1942 frame_->Push(r0); |
| 1873 | 1943 |
| 1874 // Create a new closure. | 1944 // Create a new closure. |
| 1875 __ push(cp); | 1945 frame_->Push(cp); |
| 1876 __ CallRuntime(Runtime::kNewClosure, 2); | 1946 __ CallRuntime(Runtime::kNewClosure, 2); |
| 1877 __ push(r0); | 1947 frame_->Push(r0); |
| 1878 } | 1948 } |
| 1879 | 1949 |
| 1880 | 1950 |
| 1881 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 1951 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 1882 Comment cmnt(masm_, "[ FunctionLiteral"); | 1952 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 1883 | 1953 |
| 1884 // Build the function boilerplate and instantiate it. | 1954 // Build the function boilerplate and instantiate it. |
| 1885 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 1955 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 1886 // Check for stack-overflow exception. | 1956 // Check for stack-overflow exception. |
| 1887 if (HasStackOverflow()) return; | 1957 if (HasStackOverflow()) return; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1908 Load(node->else_expression(), typeof_state()); | 1978 Load(node->else_expression(), typeof_state()); |
| 1909 __ bind(&exit); | 1979 __ bind(&exit); |
| 1910 } | 1980 } |
| 1911 | 1981 |
| 1912 | 1982 |
| 1913 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 1983 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 1914 if (slot->type() == Slot::LOOKUP) { | 1984 if (slot->type() == Slot::LOOKUP) { |
| 1915 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 1985 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 1916 | 1986 |
| 1917 // For now, just do a runtime call. | 1987 // For now, just do a runtime call. |
| 1918 __ push(cp); | 1988 frame_->Push(cp); |
| 1919 __ mov(r0, Operand(slot->var()->name())); | 1989 __ mov(r0, Operand(slot->var()->name())); |
| 1920 __ push(r0); | 1990 frame_->Push(r0); |
| 1921 | 1991 |
| 1922 if (typeof_state == INSIDE_TYPEOF) { | 1992 if (typeof_state == INSIDE_TYPEOF) { |
| 1923 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1993 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 1924 } else { | 1994 } else { |
| 1925 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1995 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1926 } | 1996 } |
| 1927 __ push(r0); | 1997 frame_->Push(r0); |
| 1928 | 1998 |
| 1929 } else { | 1999 } else { |
| 1930 // Note: We would like to keep the assert below, but it fires because of | 2000 // Note: We would like to keep the assert below, but it fires because of |
| 1931 // some nasty code in LoadTypeofExpression() which should be removed... | 2001 // some nasty code in LoadTypeofExpression() which should be removed... |
| 1932 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2002 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 1933 | 2003 |
| 1934 // Special handling for locals allocated in registers. | 2004 // Special handling for locals allocated in registers. |
| 1935 __ ldr(r0, SlotOperand(slot, r2)); | 2005 __ ldr(r0, SlotOperand(slot, r2)); |
| 1936 __ push(r0); | 2006 frame_->Push(r0); |
| 1937 if (slot->var()->mode() == Variable::CONST) { | 2007 if (slot->var()->mode() == Variable::CONST) { |
| 1938 // Const slots may contain 'the hole' value (the constant hasn't been | 2008 // Const slots may contain 'the hole' value (the constant hasn't been |
| 1939 // initialized yet) which needs to be converted into the 'undefined' | 2009 // initialized yet) which needs to be converted into the 'undefined' |
| 1940 // value. | 2010 // value. |
| 1941 Comment cmnt(masm_, "[ Unhole const"); | 2011 Comment cmnt(masm_, "[ Unhole const"); |
| 1942 __ pop(r0); | 2012 frame_->Pop(r0); |
| 1943 __ cmp(r0, Operand(Factory::the_hole_value())); | 2013 __ cmp(r0, Operand(Factory::the_hole_value())); |
| 1944 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); | 2014 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
| 1945 __ push(r0); | 2015 frame_->Push(r0); |
| 1946 } | 2016 } |
| 1947 } | 2017 } |
| 1948 } | 2018 } |
| 1949 | 2019 |
| 1950 | 2020 |
| 1951 void CodeGenerator::VisitSlot(Slot* node) { | 2021 void CodeGenerator::VisitSlot(Slot* node) { |
| 1952 Comment cmnt(masm_, "[ Slot"); | 2022 Comment cmnt(masm_, "[ Slot"); |
| 1953 LoadFromSlot(node, typeof_state()); | 2023 LoadFromSlot(node, typeof_state()); |
| 1954 } | 2024 } |
| 1955 | 2025 |
| 1956 | 2026 |
| 1957 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2027 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 1958 Comment cmnt(masm_, "[ VariableProxy"); | 2028 Comment cmnt(masm_, "[ VariableProxy"); |
| 1959 | 2029 |
| 1960 Variable* var = node->var(); | 2030 Variable* var = node->var(); |
| 1961 Expression* expr = var->rewrite(); | 2031 Expression* expr = var->rewrite(); |
| 1962 if (expr != NULL) { | 2032 if (expr != NULL) { |
| 1963 Visit(expr); | 2033 Visit(expr); |
| 1964 } else { | 2034 } else { |
| 1965 ASSERT(var->is_global()); | 2035 ASSERT(var->is_global()); |
| 1966 Reference ref(this, node); | 2036 Reference ref(this, node); |
| 1967 ref.GetValue(typeof_state()); | 2037 ref.GetValue(typeof_state()); |
| 1968 } | 2038 } |
| 1969 } | 2039 } |
| 1970 | 2040 |
| 1971 | 2041 |
| 1972 void CodeGenerator::VisitLiteral(Literal* node) { | 2042 void CodeGenerator::VisitLiteral(Literal* node) { |
| 1973 Comment cmnt(masm_, "[ Literal"); | 2043 Comment cmnt(masm_, "[ Literal"); |
| 1974 __ mov(r0, Operand(node->handle())); | 2044 __ mov(r0, Operand(node->handle())); |
| 1975 __ push(r0); | 2045 frame_->Push(r0); |
| 1976 } | 2046 } |
| 1977 | 2047 |
| 1978 | 2048 |
| 1979 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 2049 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 1980 Comment cmnt(masm_, "[ RexExp Literal"); | 2050 Comment cmnt(masm_, "[ RexExp Literal"); |
| 1981 | 2051 |
| 1982 // Retrieve the literal array and check the allocated entry. | 2052 // Retrieve the literal array and check the allocated entry. |
| 1983 | 2053 |
| 1984 // Load the function of this activation. | 2054 // Load the function of this activation. |
| 1985 __ ldr(r1, FunctionOperand()); | 2055 __ ldr(r1, frame_->Function()); |
| 1986 | 2056 |
| 1987 // Load the literals array of the function. | 2057 // Load the literals array of the function. |
| 1988 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 2058 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
| 1989 | 2059 |
| 1990 // Load the literal at the ast saved index. | 2060 // Load the literal at the ast saved index. |
| 1991 int literal_offset = | 2061 int literal_offset = |
| 1992 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2062 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
| 1993 __ ldr(r2, FieldMemOperand(r1, literal_offset)); | 2063 __ ldr(r2, FieldMemOperand(r1, literal_offset)); |
| 1994 | 2064 |
| 1995 Label done; | 2065 Label done; |
| 1996 __ cmp(r2, Operand(Factory::undefined_value())); | 2066 __ cmp(r2, Operand(Factory::undefined_value())); |
| 1997 __ b(ne, &done); | 2067 __ b(ne, &done); |
| 1998 | 2068 |
| 1999 // If the entry is undefined we call the runtime system to computed | 2069 // If the entry is undefined we call the runtime system to computed |
| 2000 // the literal. | 2070 // the literal. |
| 2001 __ push(r1); // literal array (0) | 2071 frame_->Push(r1); // literal array (0) |
| 2002 __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); | 2072 __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); |
| 2003 __ push(r0); // literal index (1) | 2073 frame_->Push(r0); // literal index (1) |
| 2004 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) | 2074 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) |
| 2005 __ push(r0); | 2075 frame_->Push(r0); |
| 2006 __ mov(r0, Operand(node->flags())); // RegExp flags (3) | 2076 __ mov(r0, Operand(node->flags())); // RegExp flags (3) |
| 2007 __ push(r0); | 2077 frame_->Push(r0); |
| 2008 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 2078 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 2009 __ mov(r2, Operand(r0)); | 2079 __ mov(r2, Operand(r0)); |
| 2010 | 2080 |
| 2011 __ bind(&done); | 2081 __ bind(&done); |
| 2012 // Push the literal. | 2082 // Push the literal. |
| 2013 __ push(r2); | 2083 frame_->Push(r2); |
| 2014 } | 2084 } |
| 2015 | 2085 |
| 2016 | 2086 |
| 2017 // This deferred code stub will be used for creating the boilerplate | 2087 // This deferred code stub will be used for creating the boilerplate |
| 2018 // by calling Runtime_CreateObjectLiteral. | 2088 // by calling Runtime_CreateObjectLiteral. |
| 2019 // Each created boilerplate is stored in the JSFunction and they are | 2089 // Each created boilerplate is stored in the JSFunction and they are |
| 2020 // therefore context dependent. | 2090 // therefore context dependent. |
| 2021 class ObjectLiteralDeferred: public DeferredCode { | 2091 class ObjectLiteralDeferred: public DeferredCode { |
| 2022 public: | 2092 public: |
| 2023 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node) | 2093 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node) |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2048 | 2118 |
| 2049 | 2119 |
| 2050 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 2120 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 2051 Comment cmnt(masm_, "[ ObjectLiteral"); | 2121 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 2052 | 2122 |
| 2053 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 2123 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
| 2054 | 2124 |
| 2055 // Retrieve the literal array and check the allocated entry. | 2125 // Retrieve the literal array and check the allocated entry. |
| 2056 | 2126 |
| 2057 // Load the function of this activation. | 2127 // Load the function of this activation. |
| 2058 __ ldr(r1, FunctionOperand()); | 2128 __ ldr(r1, frame_->Function()); |
| 2059 | 2129 |
| 2060 // Load the literals array of the function. | 2130 // Load the literals array of the function. |
| 2061 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 2131 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
| 2062 | 2132 |
| 2063 // Load the literal at the ast saved index. | 2133 // Load the literal at the ast saved index. |
| 2064 int literal_offset = | 2134 int literal_offset = |
| 2065 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2135 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
| 2066 __ ldr(r2, FieldMemOperand(r1, literal_offset)); | 2136 __ ldr(r2, FieldMemOperand(r1, literal_offset)); |
| 2067 | 2137 |
| 2068 // Check whether we need to materialize the object literal boilerplate. | 2138 // Check whether we need to materialize the object literal boilerplate. |
| 2069 // If so, jump to the deferred code. | 2139 // If so, jump to the deferred code. |
| 2070 __ cmp(r2, Operand(Factory::undefined_value())); | 2140 __ cmp(r2, Operand(Factory::undefined_value())); |
| 2071 __ b(eq, deferred->enter()); | 2141 __ b(eq, deferred->enter()); |
| 2072 __ bind(deferred->exit()); | 2142 __ bind(deferred->exit()); |
| 2073 | 2143 |
| 2074 // Push the object literal boilerplate. | 2144 // Push the object literal boilerplate. |
| 2075 __ push(r2); | 2145 frame_->Push(r2); |
| 2076 | 2146 |
| 2077 // Clone the boilerplate object. | 2147 // Clone the boilerplate object. |
| 2078 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); | 2148 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); |
| 2079 __ push(r0); // save the result | 2149 frame_->Push(r0); // save the result |
| 2080 // r0: cloned object literal | 2150 // r0: cloned object literal |
| 2081 | 2151 |
| 2082 for (int i = 0; i < node->properties()->length(); i++) { | 2152 for (int i = 0; i < node->properties()->length(); i++) { |
| 2083 ObjectLiteral::Property* property = node->properties()->at(i); | 2153 ObjectLiteral::Property* property = node->properties()->at(i); |
| 2084 Literal* key = property->key(); | 2154 Literal* key = property->key(); |
| 2085 Expression* value = property->value(); | 2155 Expression* value = property->value(); |
| 2086 switch (property->kind()) { | 2156 switch (property->kind()) { |
| 2087 case ObjectLiteral::Property::CONSTANT: break; | 2157 case ObjectLiteral::Property::CONSTANT: break; |
| 2088 case ObjectLiteral::Property::COMPUTED: // fall through | 2158 case ObjectLiteral::Property::COMPUTED: // fall through |
| 2089 case ObjectLiteral::Property::PROTOTYPE: { | 2159 case ObjectLiteral::Property::PROTOTYPE: { |
| 2090 __ push(r0); // dup the result | 2160 frame_->Push(r0); // dup the result |
| 2091 Load(key); | 2161 Load(key); |
| 2092 Load(value); | 2162 Load(value); |
| 2093 __ CallRuntime(Runtime::kSetProperty, 3); | 2163 __ CallRuntime(Runtime::kSetProperty, 3); |
| 2094 // restore r0 | 2164 // restore r0 |
| 2095 __ ldr(r0, MemOperand(sp, 0)); | 2165 __ ldr(r0, frame_->Top()); |
| 2096 break; | 2166 break; |
| 2097 } | 2167 } |
| 2098 case ObjectLiteral::Property::SETTER: { | 2168 case ObjectLiteral::Property::SETTER: { |
| 2099 __ push(r0); | 2169 frame_->Push(r0); |
| 2100 Load(key); | 2170 Load(key); |
| 2101 __ mov(r0, Operand(Smi::FromInt(1))); | 2171 __ mov(r0, Operand(Smi::FromInt(1))); |
| 2102 __ push(r0); | 2172 frame_->Push(r0); |
| 2103 Load(value); | 2173 Load(value); |
| 2104 __ CallRuntime(Runtime::kDefineAccessor, 4); | 2174 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 2105 __ ldr(r0, MemOperand(sp, 0)); | 2175 __ ldr(r0, frame_->Top()); |
| 2106 break; | 2176 break; |
| 2107 } | 2177 } |
| 2108 case ObjectLiteral::Property::GETTER: { | 2178 case ObjectLiteral::Property::GETTER: { |
| 2109 __ push(r0); | 2179 frame_->Push(r0); |
| 2110 Load(key); | 2180 Load(key); |
| 2111 __ mov(r0, Operand(Smi::FromInt(0))); | 2181 __ mov(r0, Operand(Smi::FromInt(0))); |
| 2112 __ push(r0); | 2182 frame_->Push(r0); |
| 2113 Load(value); | 2183 Load(value); |
| 2114 __ CallRuntime(Runtime::kDefineAccessor, 4); | 2184 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 2115 __ ldr(r0, MemOperand(sp, 0)); | 2185 __ ldr(r0, frame_->Top()); |
| 2116 break; | 2186 break; |
| 2117 } | 2187 } |
| 2118 } | 2188 } |
| 2119 } | 2189 } |
| 2120 } | 2190 } |
| 2121 | 2191 |
| 2122 | 2192 |
| 2123 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2193 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 2124 Comment cmnt(masm_, "[ ArrayLiteral"); | 2194 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 2125 | 2195 |
| 2126 // Call runtime to create the array literal. | 2196 // Call runtime to create the array literal. |
| 2127 __ mov(r0, Operand(node->literals())); | 2197 __ mov(r0, Operand(node->literals())); |
| 2128 __ push(r0); | 2198 frame_->Push(r0); |
| 2129 // Load the function of this frame. | 2199 // Load the function of this frame. |
| 2130 __ ldr(r0, FunctionOperand()); | 2200 __ ldr(r0, frame_->Function()); |
| 2131 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); | 2201 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); |
| 2132 __ push(r0); | 2202 frame_->Push(r0); |
| 2133 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2203 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| 2134 | 2204 |
| 2135 // Push the resulting array literal on the stack. | 2205 // Push the resulting array literal on the stack. |
| 2136 __ push(r0); | 2206 frame_->Push(r0); |
| 2137 | 2207 |
| 2138 // Generate code to set the elements in the array that are not | 2208 // Generate code to set the elements in the array that are not |
| 2139 // literals. | 2209 // literals. |
| 2140 for (int i = 0; i < node->values()->length(); i++) { | 2210 for (int i = 0; i < node->values()->length(); i++) { |
| 2141 Expression* value = node->values()->at(i); | 2211 Expression* value = node->values()->at(i); |
| 2142 | 2212 |
| 2143 // If value is literal the property value is already | 2213 // If value is literal the property value is already |
| 2144 // set in the boilerplate object. | 2214 // set in the boilerplate object. |
| 2145 if (value->AsLiteral() == NULL) { | 2215 if (value->AsLiteral() == NULL) { |
| 2146 // The property must be set by generated code. | 2216 // The property must be set by generated code. |
| 2147 Load(value); | 2217 Load(value); |
| 2148 __ pop(r0); | 2218 frame_->Pop(r0); |
| 2149 | 2219 |
| 2150 // Fetch the object literal | 2220 // Fetch the object literal |
| 2151 __ ldr(r1, MemOperand(sp, 0)); | 2221 __ ldr(r1, frame_->Top()); |
| 2152 // Get the elements array. | 2222 // Get the elements array. |
| 2153 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 2223 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
| 2154 | 2224 |
| 2155 // Write to the indexed properties array. | 2225 // Write to the indexed properties array. |
| 2156 int offset = i * kPointerSize + Array::kHeaderSize; | 2226 int offset = i * kPointerSize + Array::kHeaderSize; |
| 2157 __ str(r0, FieldMemOperand(r1, offset)); | 2227 __ str(r0, FieldMemOperand(r1, offset)); |
| 2158 | 2228 |
| 2159 // Update the write barrier for the array address. | 2229 // Update the write barrier for the array address. |
| 2160 __ mov(r3, Operand(offset)); | 2230 __ mov(r3, Operand(offset)); |
| 2161 __ RecordWrite(r1, r3, r2); | 2231 __ RecordWrite(r1, r3, r2); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2174 if (node->op() == Token::ASSIGN || | 2244 if (node->op() == Token::ASSIGN || |
| 2175 node->op() == Token::INIT_VAR || | 2245 node->op() == Token::INIT_VAR || |
| 2176 node->op() == Token::INIT_CONST) { | 2246 node->op() == Token::INIT_CONST) { |
| 2177 Load(node->value()); | 2247 Load(node->value()); |
| 2178 | 2248 |
| 2179 } else { | 2249 } else { |
| 2180 target.GetValue(NOT_INSIDE_TYPEOF); | 2250 target.GetValue(NOT_INSIDE_TYPEOF); |
| 2181 Literal* literal = node->value()->AsLiteral(); | 2251 Literal* literal = node->value()->AsLiteral(); |
| 2182 if (literal != NULL && literal->handle()->IsSmi()) { | 2252 if (literal != NULL && literal->handle()->IsSmi()) { |
| 2183 SmiOperation(node->binary_op(), literal->handle(), false); | 2253 SmiOperation(node->binary_op(), literal->handle(), false); |
| 2184 __ push(r0); | 2254 frame_->Push(r0); |
| 2185 | 2255 |
| 2186 } else { | 2256 } else { |
| 2187 Load(node->value()); | 2257 Load(node->value()); |
| 2188 GenericBinaryOperation(node->binary_op()); | 2258 GenericBinaryOperation(node->binary_op()); |
| 2189 __ push(r0); | 2259 frame_->Push(r0); |
| 2190 } | 2260 } |
| 2191 } | 2261 } |
| 2192 | 2262 |
| 2193 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 2263 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 2194 if (var != NULL && | 2264 if (var != NULL && |
| 2195 (var->mode() == Variable::CONST) && | 2265 (var->mode() == Variable::CONST) && |
| 2196 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 2266 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
| 2197 // Assignment ignored - leave the value on the stack. | 2267 // Assignment ignored - leave the value on the stack. |
| 2198 | 2268 |
| 2199 } else { | 2269 } else { |
| 2200 __ RecordPosition(node->position()); | 2270 __ RecordPosition(node->position()); |
| 2201 if (node->op() == Token::INIT_CONST) { | 2271 if (node->op() == Token::INIT_CONST) { |
| 2202 // Dynamic constant initializations must use the function context | 2272 // Dynamic constant initializations must use the function context |
| 2203 // and initialize the actual constant declared. Dynamic variable | 2273 // and initialize the actual constant declared. Dynamic variable |
| 2204 // initializations are simply assignments and use SetValue. | 2274 // initializations are simply assignments and use SetValue. |
| 2205 target.SetValue(CONST_INIT); | 2275 target.SetValue(CONST_INIT); |
| 2206 } else { | 2276 } else { |
| 2207 target.SetValue(NOT_CONST_INIT); | 2277 target.SetValue(NOT_CONST_INIT); |
| 2208 } | 2278 } |
| 2209 } | 2279 } |
| 2210 } | 2280 } |
| 2211 | 2281 |
| 2212 | 2282 |
| 2213 void CodeGenerator::VisitThrow(Throw* node) { | 2283 void CodeGenerator::VisitThrow(Throw* node) { |
| 2214 Comment cmnt(masm_, "[ Throw"); | 2284 Comment cmnt(masm_, "[ Throw"); |
| 2215 | 2285 |
| 2216 Load(node->exception()); | 2286 Load(node->exception()); |
| 2217 __ RecordPosition(node->position()); | 2287 __ RecordPosition(node->position()); |
| 2218 __ CallRuntime(Runtime::kThrow, 1); | 2288 __ CallRuntime(Runtime::kThrow, 1); |
| 2219 __ push(r0); | 2289 frame_->Push(r0); |
| 2220 } | 2290 } |
| 2221 | 2291 |
| 2222 | 2292 |
| 2223 void CodeGenerator::VisitProperty(Property* node) { | 2293 void CodeGenerator::VisitProperty(Property* node) { |
| 2224 Comment cmnt(masm_, "[ Property"); | 2294 Comment cmnt(masm_, "[ Property"); |
| 2225 | 2295 |
| 2226 Reference property(this, node); | 2296 Reference property(this, node); |
| 2227 property.GetValue(typeof_state()); | 2297 property.GetValue(typeof_state()); |
| 2228 } | 2298 } |
| 2229 | 2299 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2250 // is resolved in cache misses (this also holds for megamorphic calls). | 2320 // is resolved in cache misses (this also holds for megamorphic calls). |
| 2251 // ------------------------------------------------------------------------ | 2321 // ------------------------------------------------------------------------ |
| 2252 | 2322 |
| 2253 if (var != NULL && !var->is_this() && var->is_global()) { | 2323 if (var != NULL && !var->is_this() && var->is_global()) { |
| 2254 // ---------------------------------- | 2324 // ---------------------------------- |
| 2255 // JavaScript example: 'foo(1, 2, 3)' // foo is global | 2325 // JavaScript example: 'foo(1, 2, 3)' // foo is global |
| 2256 // ---------------------------------- | 2326 // ---------------------------------- |
| 2257 | 2327 |
| 2258 // Push the name of the function and the receiver onto the stack. | 2328 // Push the name of the function and the receiver onto the stack. |
| 2259 __ mov(r0, Operand(var->name())); | 2329 __ mov(r0, Operand(var->name())); |
| 2260 __ push(r0); | 2330 frame_->Push(r0); |
| 2261 | 2331 |
| 2262 // Pass the global object as the receiver and let the IC stub | 2332 // Pass the global object as the receiver and let the IC stub |
| 2263 // patch the stack to use the global proxy as 'this' in the | 2333 // patch the stack to use the global proxy as 'this' in the |
| 2264 // invoked function. | 2334 // invoked function. |
| 2265 LoadGlobal(); | 2335 LoadGlobal(); |
| 2266 | 2336 |
| 2267 // Load the arguments. | 2337 // Load the arguments. |
| 2268 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2338 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| 2269 | 2339 |
| 2270 // Setup the receiver register and call the IC initialization code. | 2340 // Setup the receiver register and call the IC initialization code. |
| 2271 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2341 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 2272 __ RecordPosition(node->position()); | 2342 __ RecordPosition(node->position()); |
| 2273 __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT); | 2343 __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT); |
| 2274 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2344 __ ldr(cp, frame_->Context()); |
| 2275 // Remove the function from the stack. | 2345 // Remove the function from the stack. |
| 2276 __ pop(); | 2346 frame_->Pop(); |
| 2277 __ push(r0); | 2347 frame_->Push(r0); |
| 2278 | 2348 |
| 2279 } else if (var != NULL && var->slot() != NULL && | 2349 } else if (var != NULL && var->slot() != NULL && |
| 2280 var->slot()->type() == Slot::LOOKUP) { | 2350 var->slot()->type() == Slot::LOOKUP) { |
| 2281 // ---------------------------------- | 2351 // ---------------------------------- |
| 2282 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj | 2352 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj |
| 2283 // ---------------------------------- | 2353 // ---------------------------------- |
| 2284 | 2354 |
| 2285 // Load the function | 2355 // Load the function |
| 2286 __ push(cp); | 2356 frame_->Push(cp); |
| 2287 __ mov(r0, Operand(var->name())); | 2357 __ mov(r0, Operand(var->name())); |
| 2288 __ push(r0); | 2358 frame_->Push(r0); |
| 2289 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2359 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2290 // r0: slot value; r1: receiver | 2360 // r0: slot value; r1: receiver |
| 2291 | 2361 |
| 2292 // Load the receiver. | 2362 // Load the receiver. |
| 2293 __ push(r0); // function | 2363 frame_->Push(r0); // function |
| 2294 __ push(r1); // receiver | 2364 frame_->Push(r1); // receiver |
| 2295 | 2365 |
| 2296 // Call the function. | 2366 // Call the function. |
| 2297 CallWithArguments(args, node->position()); | 2367 CallWithArguments(args, node->position()); |
| 2298 __ push(r0); | 2368 frame_->Push(r0); |
| 2299 | 2369 |
| 2300 } else if (property != NULL) { | 2370 } else if (property != NULL) { |
| 2301 // Check if the key is a literal string. | 2371 // Check if the key is a literal string. |
| 2302 Literal* literal = property->key()->AsLiteral(); | 2372 Literal* literal = property->key()->AsLiteral(); |
| 2303 | 2373 |
| 2304 if (literal != NULL && literal->handle()->IsSymbol()) { | 2374 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 2305 // ------------------------------------------------------------------ | 2375 // ------------------------------------------------------------------ |
| 2306 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 2376 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
| 2307 // ------------------------------------------------------------------ | 2377 // ------------------------------------------------------------------ |
| 2308 | 2378 |
| 2309 // Push the name of the function and the receiver onto the stack. | 2379 // Push the name of the function and the receiver onto the stack. |
| 2310 __ mov(r0, Operand(literal->handle())); | 2380 __ mov(r0, Operand(literal->handle())); |
| 2311 __ push(r0); | 2381 frame_->Push(r0); |
| 2312 Load(property->obj()); | 2382 Load(property->obj()); |
| 2313 | 2383 |
| 2314 // Load the arguments. | 2384 // Load the arguments. |
| 2315 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2385 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| 2316 | 2386 |
| 2317 // Set the receiver register and call the IC initialization code. | 2387 // Set the receiver register and call the IC initialization code. |
| 2318 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2388 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 2319 __ RecordPosition(node->position()); | 2389 __ RecordPosition(node->position()); |
| 2320 __ Call(stub, RelocInfo::CODE_TARGET); | 2390 __ Call(stub, RelocInfo::CODE_TARGET); |
| 2321 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2391 __ ldr(cp, frame_->Context()); |
| 2322 | 2392 |
| 2323 // Remove the function from the stack. | 2393 // Remove the function from the stack. |
| 2324 __ pop(); | 2394 frame_->Pop(); |
| 2325 | 2395 |
| 2326 __ push(r0); // push after get rid of function from the stack | 2396 frame_->Push(r0); // push after get rid of function from the stack |
| 2327 | 2397 |
| 2328 } else { | 2398 } else { |
| 2329 // ------------------------------------------- | 2399 // ------------------------------------------- |
| 2330 // JavaScript example: 'array[index](1, 2, 3)' | 2400 // JavaScript example: 'array[index](1, 2, 3)' |
| 2331 // ------------------------------------------- | 2401 // ------------------------------------------- |
| 2332 | 2402 |
| 2333 // Load the function to call from the property through a reference. | 2403 // Load the function to call from the property through a reference. |
| 2334 Reference ref(this, property); | 2404 Reference ref(this, property); |
| 2335 ref.GetValue(NOT_INSIDE_TYPEOF); // receiver | 2405 ref.GetValue(NOT_INSIDE_TYPEOF); // receiver |
| 2336 | 2406 |
| 2337 // Pass receiver to called function. | 2407 // Pass receiver to called function. |
| 2338 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize)); | 2408 __ ldr(r0, frame_->Element(ref.size())); |
| 2339 __ push(r0); | 2409 frame_->Push(r0); |
| 2340 // Call the function. | 2410 // Call the function. |
| 2341 CallWithArguments(args, node->position()); | 2411 CallWithArguments(args, node->position()); |
| 2342 __ push(r0); | 2412 frame_->Push(r0); |
| 2343 } | 2413 } |
| 2344 | 2414 |
| 2345 } else { | 2415 } else { |
| 2346 // ---------------------------------- | 2416 // ---------------------------------- |
| 2347 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 2417 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
| 2348 // ---------------------------------- | 2418 // ---------------------------------- |
| 2349 | 2419 |
| 2350 // Load the function. | 2420 // Load the function. |
| 2351 Load(function); | 2421 Load(function); |
| 2352 | 2422 |
| 2353 // Pass the global proxy as the receiver. | 2423 // Pass the global proxy as the receiver. |
| 2354 LoadGlobalReceiver(r0); | 2424 LoadGlobalReceiver(r0); |
| 2355 | 2425 |
| 2356 // Call the function. | 2426 // Call the function. |
| 2357 CallWithArguments(args, node->position()); | 2427 CallWithArguments(args, node->position()); |
| 2358 __ push(r0); | 2428 frame_->Push(r0); |
| 2359 } | 2429 } |
| 2360 } | 2430 } |
| 2361 | 2431 |
| 2362 | 2432 |
| 2363 void CodeGenerator::VisitCallNew(CallNew* node) { | 2433 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 2364 Comment cmnt(masm_, "[ CallNew"); | 2434 Comment cmnt(masm_, "[ CallNew"); |
| 2365 | 2435 |
| 2366 // According to ECMA-262, section 11.2.2, page 44, the function | 2436 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2367 // expression in new calls must be evaluated before the | 2437 // expression in new calls must be evaluated before the |
| 2368 // arguments. This is different from ordinary calls, where the | 2438 // arguments. This is different from ordinary calls, where the |
| 2369 // actual function to call is resolved after the arguments have been | 2439 // actual function to call is resolved after the arguments have been |
| 2370 // evaluated. | 2440 // evaluated. |
| 2371 | 2441 |
| 2372 // Compute function to call and use the global object as the | 2442 // Compute function to call and use the global object as the |
| 2373 // receiver. There is no need to use the global proxy here because | 2443 // receiver. There is no need to use the global proxy here because |
| 2374 // it will always be replaced with a newly allocated object. | 2444 // it will always be replaced with a newly allocated object. |
| 2375 Load(node->expression()); | 2445 Load(node->expression()); |
| 2376 LoadGlobal(); | 2446 LoadGlobal(); |
| 2377 | 2447 |
| 2378 // Push the arguments ("left-to-right") on the stack. | 2448 // Push the arguments ("left-to-right") on the stack. |
| 2379 ZoneList<Expression*>* args = node->arguments(); | 2449 ZoneList<Expression*>* args = node->arguments(); |
| 2380 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2450 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| 2381 | 2451 |
| 2382 // r0: the number of arguments. | 2452 // r0: the number of arguments. |
| 2383 __ mov(r0, Operand(args->length())); | 2453 __ mov(r0, Operand(args->length())); |
| 2384 | 2454 |
| 2385 // Load the function into r1 as per calling convention. | 2455 // Load the function into r1 as per calling convention. |
| 2386 __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize)); | 2456 __ ldr(r1, frame_->Element(args->length() + 1)); |
| 2387 | 2457 |
| 2388 // Call the construct call builtin that handles allocation and | 2458 // Call the construct call builtin that handles allocation and |
| 2389 // constructor invocation. | 2459 // constructor invocation. |
| 2390 __ RecordPosition(RelocInfo::POSITION); | 2460 __ RecordPosition(RelocInfo::POSITION); |
| 2391 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | 2461 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), |
| 2392 RelocInfo::CONSTRUCT_CALL); | 2462 RelocInfo::CONSTRUCT_CALL); |
| 2393 | 2463 |
| 2394 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). | 2464 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). |
| 2395 __ str(r0, MemOperand(sp, 0 * kPointerSize)); | 2465 __ str(r0, frame_->Top()); |
| 2396 } | 2466 } |
| 2397 | 2467 |
| 2398 | 2468 |
| 2399 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 2469 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 2400 ASSERT(args->length() == 1); | 2470 ASSERT(args->length() == 1); |
| 2401 Label leave; | 2471 Label leave; |
| 2402 Load(args->at(0)); | 2472 Load(args->at(0)); |
| 2403 __ pop(r0); // r0 contains object. | 2473 frame_->Pop(r0); // r0 contains object. |
| 2404 // if (object->IsSmi()) return the object. | 2474 // if (object->IsSmi()) return the object. |
| 2405 __ tst(r0, Operand(kSmiTagMask)); | 2475 __ tst(r0, Operand(kSmiTagMask)); |
| 2406 __ b(eq, &leave); | 2476 __ b(eq, &leave); |
| 2407 // It is a heap object - get map. | 2477 // It is a heap object - get map. |
| 2408 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2478 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2409 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 2479 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 2410 // if (!object->IsJSValue()) return the object. | 2480 // if (!object->IsJSValue()) return the object. |
| 2411 __ cmp(r1, Operand(JS_VALUE_TYPE)); | 2481 __ cmp(r1, Operand(JS_VALUE_TYPE)); |
| 2412 __ b(ne, &leave); | 2482 __ b(ne, &leave); |
| 2413 // Load the value. | 2483 // Load the value. |
| 2414 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); | 2484 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); |
| 2415 __ bind(&leave); | 2485 __ bind(&leave); |
| 2416 __ push(r0); | 2486 frame_->Push(r0); |
| 2417 } | 2487 } |
| 2418 | 2488 |
| 2419 | 2489 |
| 2420 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 2490 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 2421 ASSERT(args->length() == 2); | 2491 ASSERT(args->length() == 2); |
| 2422 Label leave; | 2492 Label leave; |
| 2423 Load(args->at(0)); // Load the object. | 2493 Load(args->at(0)); // Load the object. |
| 2424 Load(args->at(1)); // Load the value. | 2494 Load(args->at(1)); // Load the value. |
| 2425 __ pop(r0); // r0 contains value | 2495 frame_->Pop(r0); // r0 contains value |
| 2426 __ pop(r1); // r1 contains object | 2496 frame_->Pop(r1); // r1 contains object |
| 2427 // if (object->IsSmi()) return object. | 2497 // if (object->IsSmi()) return object. |
| 2428 __ tst(r1, Operand(kSmiTagMask)); | 2498 __ tst(r1, Operand(kSmiTagMask)); |
| 2429 __ b(eq, &leave); | 2499 __ b(eq, &leave); |
| 2430 // It is a heap object - get map. | 2500 // It is a heap object - get map. |
| 2431 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 2501 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 2432 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 2502 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 2433 // if (!object->IsJSValue()) return object. | 2503 // if (!object->IsJSValue()) return object. |
| 2434 __ cmp(r2, Operand(JS_VALUE_TYPE)); | 2504 __ cmp(r2, Operand(JS_VALUE_TYPE)); |
| 2435 __ b(ne, &leave); | 2505 __ b(ne, &leave); |
| 2436 // Store the value. | 2506 // Store the value. |
| 2437 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); | 2507 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); |
| 2438 // Update the write barrier. | 2508 // Update the write barrier. |
| 2439 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); | 2509 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); |
| 2440 __ RecordWrite(r1, r2, r3); | 2510 __ RecordWrite(r1, r2, r3); |
| 2441 // Leave. | 2511 // Leave. |
| 2442 __ bind(&leave); | 2512 __ bind(&leave); |
| 2443 __ push(r0); | 2513 frame_->Push(r0); |
| 2444 } | 2514 } |
| 2445 | 2515 |
| 2446 | 2516 |
| 2447 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2517 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 2448 ASSERT(args->length() == 1); | 2518 ASSERT(args->length() == 1); |
| 2449 Load(args->at(0)); | 2519 Load(args->at(0)); |
| 2450 __ pop(r0); | 2520 frame_->Pop(r0); |
| 2451 __ tst(r0, Operand(kSmiTagMask)); | 2521 __ tst(r0, Operand(kSmiTagMask)); |
| 2452 cc_reg_ = eq; | 2522 cc_reg_ = eq; |
| 2453 } | 2523 } |
| 2454 | 2524 |
| 2455 | 2525 |
| 2456 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2526 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 2457 ASSERT(args->length() == 1); | 2527 ASSERT(args->length() == 1); |
| 2458 Load(args->at(0)); | 2528 Load(args->at(0)); |
| 2459 __ pop(r0); | 2529 frame_->Pop(r0); |
| 2460 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); | 2530 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); |
| 2461 cc_reg_ = eq; | 2531 cc_reg_ = eq; |
| 2462 } | 2532 } |
| 2463 | 2533 |
| 2464 | 2534 |
| 2465 // This should generate code that performs a charCodeAt() call or returns | 2535 // This should generate code that performs a charCodeAt() call or returns |
| 2466 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 2536 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 2467 // It is not yet implemented on ARM, so it always goes to the slow case. | 2537 // It is not yet implemented on ARM, so it always goes to the slow case. |
| 2468 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 2538 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 2469 ASSERT(args->length() == 2); | 2539 ASSERT(args->length() == 2); |
| 2470 __ mov(r0, Operand(Factory::undefined_value())); | 2540 __ mov(r0, Operand(Factory::undefined_value())); |
| 2471 __ push(r0); | 2541 frame_->Push(r0); |
| 2472 } | 2542 } |
| 2473 | 2543 |
| 2474 | 2544 |
| 2475 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 2545 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 2476 ASSERT(args->length() == 1); | 2546 ASSERT(args->length() == 1); |
| 2477 Load(args->at(0)); | 2547 Load(args->at(0)); |
| 2478 Label answer; | 2548 Label answer; |
| 2479 // We need the CC bits to come out as not_equal in the case where the | 2549 // We need the CC bits to come out as not_equal in the case where the |
| 2480 // object is a smi. This can't be done with the usual test opcode so | 2550 // object is a smi. This can't be done with the usual test opcode so |
| 2481 // we use XOR to get the right CC bits. | 2551 // we use XOR to get the right CC bits. |
| 2482 __ pop(r0); | 2552 frame_->Pop(r0); |
| 2483 __ and_(r1, r0, Operand(kSmiTagMask)); | 2553 __ and_(r1, r0, Operand(kSmiTagMask)); |
| 2484 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); | 2554 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
| 2485 __ b(ne, &answer); | 2555 __ b(ne, &answer); |
| 2486 // It is a heap object - get the map. | 2556 // It is a heap object - get the map. |
| 2487 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2557 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2488 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 2558 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 2489 // Check if the object is a JS array or not. | 2559 // Check if the object is a JS array or not. |
| 2490 __ cmp(r1, Operand(JS_ARRAY_TYPE)); | 2560 __ cmp(r1, Operand(JS_ARRAY_TYPE)); |
| 2491 __ bind(&answer); | 2561 __ bind(&answer); |
| 2492 cc_reg_ = eq; | 2562 cc_reg_ = eq; |
| 2493 } | 2563 } |
| 2494 | 2564 |
| 2495 | 2565 |
| 2496 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 2566 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
| 2497 ASSERT(args->length() == 0); | 2567 ASSERT(args->length() == 0); |
| 2498 | 2568 |
| 2499 // Seed the result with the formal parameters count, which will be used | 2569 // Seed the result with the formal parameters count, which will be used |
| 2500 // in case no arguments adaptor frame is found below the current frame. | 2570 // in case no arguments adaptor frame is found below the current frame. |
| 2501 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); | 2571 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| 2502 | 2572 |
| 2503 // Call the shared stub to get to the arguments.length. | 2573 // Call the shared stub to get to the arguments.length. |
| 2504 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 2574 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 2505 __ CallStub(&stub); | 2575 __ CallStub(&stub); |
| 2506 __ push(r0); | 2576 frame_->Push(r0); |
| 2507 } | 2577 } |
| 2508 | 2578 |
| 2509 | 2579 |
| 2510 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 2580 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 2511 ASSERT(args->length() == 1); | 2581 ASSERT(args->length() == 1); |
| 2512 | 2582 |
| 2513 // Satisfy contract with ArgumentsAccessStub: | 2583 // Satisfy contract with ArgumentsAccessStub: |
| 2514 // Load the key into r1 and the formal parameters count into r0. | 2584 // Load the key into r1 and the formal parameters count into r0. |
| 2515 Load(args->at(0)); | 2585 Load(args->at(0)); |
| 2516 __ pop(r1); | 2586 frame_->Pop(r1); |
| 2517 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); | 2587 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| 2518 | 2588 |
| 2519 // Call the shared stub to get to arguments[key]. | 2589 // Call the shared stub to get to arguments[key]. |
| 2520 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2590 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2521 __ CallStub(&stub); | 2591 __ CallStub(&stub); |
| 2522 __ push(r0); | 2592 frame_->Push(r0); |
| 2523 } | 2593 } |
| 2524 | 2594 |
| 2525 | 2595 |
| 2526 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 2596 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 2527 ASSERT(args->length() == 2); | 2597 ASSERT(args->length() == 2); |
| 2528 | 2598 |
| 2529 // Load the two objects into registers and perform the comparison. | 2599 // Load the two objects into registers and perform the comparison. |
| 2530 Load(args->at(0)); | 2600 Load(args->at(0)); |
| 2531 Load(args->at(1)); | 2601 Load(args->at(1)); |
| 2532 __ pop(r0); | 2602 frame_->Pop(r0); |
| 2533 __ pop(r1); | 2603 frame_->Pop(r1); |
| 2534 __ cmp(r0, Operand(r1)); | 2604 __ cmp(r0, Operand(r1)); |
| 2535 cc_reg_ = eq; | 2605 cc_reg_ = eq; |
| 2536 } | 2606 } |
| 2537 | 2607 |
| 2538 | 2608 |
| 2539 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 2609 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 2540 if (CheckForInlineRuntimeCall(node)) return; | 2610 if (CheckForInlineRuntimeCall(node)) return; |
| 2541 | 2611 |
| 2542 ZoneList<Expression*>* args = node->arguments(); | 2612 ZoneList<Expression*>* args = node->arguments(); |
| 2543 Comment cmnt(masm_, "[ CallRuntime"); | 2613 Comment cmnt(masm_, "[ CallRuntime"); |
| 2544 Runtime::Function* function = node->function(); | 2614 Runtime::Function* function = node->function(); |
| 2545 | 2615 |
| 2546 if (function != NULL) { | 2616 if (function != NULL) { |
| 2547 // Push the arguments ("left-to-right"). | 2617 // Push the arguments ("left-to-right"). |
| 2548 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2618 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| 2549 | 2619 |
| 2550 // Call the C runtime function. | 2620 // Call the C runtime function. |
| 2551 __ CallRuntime(function, args->length()); | 2621 __ CallRuntime(function, args->length()); |
| 2552 __ push(r0); | 2622 frame_->Push(r0); |
| 2553 | 2623 |
| 2554 } else { | 2624 } else { |
| 2555 // Prepare stack for calling JS runtime function. | 2625 // Prepare stack for calling JS runtime function. |
| 2556 __ mov(r0, Operand(node->name())); | 2626 __ mov(r0, Operand(node->name())); |
| 2557 __ push(r0); | 2627 frame_->Push(r0); |
| 2558 // Push the builtins object found in the current global object. | 2628 // Push the builtins object found in the current global object. |
| 2559 __ ldr(r1, GlobalObject()); | 2629 __ ldr(r1, GlobalObject()); |
| 2560 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); | 2630 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); |
| 2561 __ push(r0); | 2631 frame_->Push(r0); |
| 2562 | 2632 |
| 2563 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2633 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| 2564 | 2634 |
| 2565 // Call the JS runtime function. | 2635 // Call the JS runtime function. |
| 2566 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2636 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 2567 __ Call(stub, RelocInfo::CODE_TARGET); | 2637 __ Call(stub, RelocInfo::CODE_TARGET); |
| 2568 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2638 __ ldr(cp, frame_->Context()); |
| 2569 __ pop(); | 2639 frame_->Pop(); |
| 2570 __ push(r0); | 2640 frame_->Push(r0); |
| 2571 } | 2641 } |
| 2572 } | 2642 } |
| 2573 | 2643 |
| 2574 | 2644 |
| 2575 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 2645 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 2576 Comment cmnt(masm_, "[ UnaryOperation"); | 2646 Comment cmnt(masm_, "[ UnaryOperation"); |
| 2577 | 2647 |
| 2578 Token::Value op = node->op(); | 2648 Token::Value op = node->op(); |
| 2579 | 2649 |
| 2580 if (op == Token::NOT) { | 2650 if (op == Token::NOT) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2592 Load(property->obj()); | 2662 Load(property->obj()); |
| 2593 Load(property->key()); | 2663 Load(property->key()); |
| 2594 __ mov(r0, Operand(1)); // not counting receiver | 2664 __ mov(r0, Operand(1)); // not counting receiver |
| 2595 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); | 2665 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
| 2596 | 2666 |
| 2597 } else if (variable != NULL) { | 2667 } else if (variable != NULL) { |
| 2598 Slot* slot = variable->slot(); | 2668 Slot* slot = variable->slot(); |
| 2599 if (variable->is_global()) { | 2669 if (variable->is_global()) { |
| 2600 LoadGlobal(); | 2670 LoadGlobal(); |
| 2601 __ mov(r0, Operand(variable->name())); | 2671 __ mov(r0, Operand(variable->name())); |
| 2602 __ push(r0); | 2672 frame_->Push(r0); |
| 2603 __ mov(r0, Operand(1)); // not counting receiver | 2673 __ mov(r0, Operand(1)); // not counting receiver |
| 2604 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); | 2674 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
| 2605 | 2675 |
| 2606 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 2676 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 2607 // lookup the context holding the named variable | 2677 // lookup the context holding the named variable |
| 2608 __ push(cp); | 2678 frame_->Push(cp); |
| 2609 __ mov(r0, Operand(variable->name())); | 2679 __ mov(r0, Operand(variable->name())); |
| 2610 __ push(r0); | 2680 frame_->Push(r0); |
| 2611 __ CallRuntime(Runtime::kLookupContext, 2); | 2681 __ CallRuntime(Runtime::kLookupContext, 2); |
| 2612 // r0: context | 2682 // r0: context |
| 2613 __ push(r0); | 2683 frame_->Push(r0); |
| 2614 __ mov(r0, Operand(variable->name())); | 2684 __ mov(r0, Operand(variable->name())); |
| 2615 __ push(r0); | 2685 frame_->Push(r0); |
| 2616 __ mov(r0, Operand(1)); // not counting receiver | 2686 __ mov(r0, Operand(1)); // not counting receiver |
| 2617 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); | 2687 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
| 2618 | 2688 |
| 2619 } else { | 2689 } else { |
| 2620 // Default: Result of deleting non-global, not dynamically | 2690 // Default: Result of deleting non-global, not dynamically |
| 2621 // introduced variables is false. | 2691 // introduced variables is false. |
| 2622 __ mov(r0, Operand(Factory::false_value())); | 2692 __ mov(r0, Operand(Factory::false_value())); |
| 2623 } | 2693 } |
| 2624 | 2694 |
| 2625 } else { | 2695 } else { |
| 2626 // Default: Result of deleting expressions is true. | 2696 // Default: Result of deleting expressions is true. |
| 2627 Load(node->expression()); // may have side-effects | 2697 Load(node->expression()); // may have side-effects |
| 2628 __ pop(); | 2698 frame_->Pop(); |
| 2629 __ mov(r0, Operand(Factory::true_value())); | 2699 __ mov(r0, Operand(Factory::true_value())); |
| 2630 } | 2700 } |
| 2631 __ push(r0); | 2701 frame_->Push(r0); |
| 2632 | 2702 |
| 2633 } else if (op == Token::TYPEOF) { | 2703 } else if (op == Token::TYPEOF) { |
| 2634 // Special case for loading the typeof expression; see comment on | 2704 // Special case for loading the typeof expression; see comment on |
| 2635 // LoadTypeofExpression(). | 2705 // LoadTypeofExpression(). |
| 2636 LoadTypeofExpression(node->expression()); | 2706 LoadTypeofExpression(node->expression()); |
| 2637 __ CallRuntime(Runtime::kTypeof, 1); | 2707 __ CallRuntime(Runtime::kTypeof, 1); |
| 2638 __ push(r0); // r0 has result | 2708 frame_->Push(r0); // r0 has result |
| 2639 | 2709 |
| 2640 } else { | 2710 } else { |
| 2641 Load(node->expression()); | 2711 Load(node->expression()); |
| 2642 __ pop(r0); | 2712 frame_->Pop(r0); |
| 2643 switch (op) { | 2713 switch (op) { |
| 2644 case Token::NOT: | 2714 case Token::NOT: |
| 2645 case Token::DELETE: | 2715 case Token::DELETE: |
| 2646 case Token::TYPEOF: | 2716 case Token::TYPEOF: |
| 2647 UNREACHABLE(); // handled above | 2717 UNREACHABLE(); // handled above |
| 2648 break; | 2718 break; |
| 2649 | 2719 |
| 2650 case Token::SUB: { | 2720 case Token::SUB: { |
| 2651 UnarySubStub stub; | 2721 UnarySubStub stub; |
| 2652 __ CallStub(&stub); | 2722 __ CallStub(&stub); |
| 2653 break; | 2723 break; |
| 2654 } | 2724 } |
| 2655 | 2725 |
| 2656 case Token::BIT_NOT: { | 2726 case Token::BIT_NOT: { |
| 2657 // smi check | 2727 // smi check |
| 2658 Label smi_label; | 2728 Label smi_label; |
| 2659 Label continue_label; | 2729 Label continue_label; |
| 2660 __ tst(r0, Operand(kSmiTagMask)); | 2730 __ tst(r0, Operand(kSmiTagMask)); |
| 2661 __ b(eq, &smi_label); | 2731 __ b(eq, &smi_label); |
| 2662 | 2732 |
| 2663 __ push(r0); | 2733 frame_->Push(r0); |
| 2664 __ mov(r0, Operand(0)); // not counting receiver | 2734 __ mov(r0, Operand(0)); // not counting receiver |
| 2665 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS); | 2735 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS); |
| 2666 | 2736 |
| 2667 __ b(&continue_label); | 2737 __ b(&continue_label); |
| 2668 __ bind(&smi_label); | 2738 __ bind(&smi_label); |
| 2669 __ mvn(r0, Operand(r0)); | 2739 __ mvn(r0, Operand(r0)); |
| 2670 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag | 2740 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag |
| 2671 __ bind(&continue_label); | 2741 __ bind(&continue_label); |
| 2672 break; | 2742 break; |
| 2673 } | 2743 } |
| 2674 | 2744 |
| 2675 case Token::VOID: | 2745 case Token::VOID: |
| 2676 // since the stack top is cached in r0, popping and then | 2746 // since the stack top is cached in r0, popping and then |
| 2677 // pushing a value can be done by just writing to r0. | 2747 // pushing a value can be done by just writing to r0. |
| 2678 __ mov(r0, Operand(Factory::undefined_value())); | 2748 __ mov(r0, Operand(Factory::undefined_value())); |
| 2679 break; | 2749 break; |
| 2680 | 2750 |
| 2681 case Token::ADD: { | 2751 case Token::ADD: { |
| 2682 // Smi check. | 2752 // Smi check. |
| 2683 Label continue_label; | 2753 Label continue_label; |
| 2684 __ tst(r0, Operand(kSmiTagMask)); | 2754 __ tst(r0, Operand(kSmiTagMask)); |
| 2685 __ b(eq, &continue_label); | 2755 __ b(eq, &continue_label); |
| 2686 __ push(r0); | 2756 frame_->Push(r0); |
| 2687 __ mov(r0, Operand(0)); // not counting receiver | 2757 __ mov(r0, Operand(0)); // not counting receiver |
| 2688 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); | 2758 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); |
| 2689 __ bind(&continue_label); | 2759 __ bind(&continue_label); |
| 2690 break; | 2760 break; |
| 2691 } | 2761 } |
| 2692 default: | 2762 default: |
| 2693 UNREACHABLE(); | 2763 UNREACHABLE(); |
| 2694 } | 2764 } |
| 2695 __ push(r0); // r0 has result | 2765 frame_->Push(r0); // r0 has result |
| 2696 } | 2766 } |
| 2697 } | 2767 } |
| 2698 | 2768 |
| 2699 | 2769 |
| 2700 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 2770 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 2701 Comment cmnt(masm_, "[ CountOperation"); | 2771 Comment cmnt(masm_, "[ CountOperation"); |
| 2702 | 2772 |
| 2703 bool is_postfix = node->is_postfix(); | 2773 bool is_postfix = node->is_postfix(); |
| 2704 bool is_increment = node->op() == Token::INC; | 2774 bool is_increment = node->op() == Token::INC; |
| 2705 | 2775 |
| 2706 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 2776 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 2707 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 2777 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 2708 | 2778 |
| 2709 // Postfix: Make room for the result. | 2779 // Postfix: Make room for the result. |
| 2710 if (is_postfix) { | 2780 if (is_postfix) { |
| 2711 __ mov(r0, Operand(0)); | 2781 __ mov(r0, Operand(0)); |
| 2712 __ push(r0); | 2782 frame_->Push(r0); |
| 2713 } | 2783 } |
| 2714 | 2784 |
| 2715 { Reference target(this, node->expression()); | 2785 { Reference target(this, node->expression()); |
| 2716 if (target.is_illegal()) return; | 2786 if (target.is_illegal()) return; |
| 2717 target.GetValue(NOT_INSIDE_TYPEOF); | 2787 target.GetValue(NOT_INSIDE_TYPEOF); |
| 2718 __ pop(r0); | 2788 frame_->Pop(r0); |
| 2719 | 2789 |
| 2720 Label slow, exit; | 2790 Label slow, exit; |
| 2721 | 2791 |
| 2722 // Load the value (1) into register r1. | 2792 // Load the value (1) into register r1. |
| 2723 __ mov(r1, Operand(Smi::FromInt(1))); | 2793 __ mov(r1, Operand(Smi::FromInt(1))); |
| 2724 | 2794 |
| 2725 // Check for smi operand. | 2795 // Check for smi operand. |
| 2726 __ tst(r0, Operand(kSmiTagMask)); | 2796 __ tst(r0, Operand(kSmiTagMask)); |
| 2727 __ b(ne, &slow); | 2797 __ b(ne, &slow); |
| 2728 | 2798 |
| 2729 // Postfix: Store the old value as the result. | 2799 // Postfix: Store the old value as the result. |
| 2730 if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize)); | 2800 if (is_postfix) { |
| 2801 __ str(r0, frame_->Element(target.size())); |
| 2802 } |
| 2731 | 2803 |
| 2732 // Perform optimistic increment/decrement. | 2804 // Perform optimistic increment/decrement. |
| 2733 if (is_increment) { | 2805 if (is_increment) { |
| 2734 __ add(r0, r0, Operand(r1), SetCC); | 2806 __ add(r0, r0, Operand(r1), SetCC); |
| 2735 } else { | 2807 } else { |
| 2736 __ sub(r0, r0, Operand(r1), SetCC); | 2808 __ sub(r0, r0, Operand(r1), SetCC); |
| 2737 } | 2809 } |
| 2738 | 2810 |
| 2739 // If the increment/decrement didn't overflow, we're done. | 2811 // If the increment/decrement didn't overflow, we're done. |
| 2740 __ b(vc, &exit); | 2812 __ b(vc, &exit); |
| 2741 | 2813 |
| 2742 // Revert optimistic increment/decrement. | 2814 // Revert optimistic increment/decrement. |
| 2743 if (is_increment) { | 2815 if (is_increment) { |
| 2744 __ sub(r0, r0, Operand(r1)); | 2816 __ sub(r0, r0, Operand(r1)); |
| 2745 } else { | 2817 } else { |
| 2746 __ add(r0, r0, Operand(r1)); | 2818 __ add(r0, r0, Operand(r1)); |
| 2747 } | 2819 } |
| 2748 | 2820 |
| 2749 // Slow case: Convert to number. | 2821 // Slow case: Convert to number. |
| 2750 __ bind(&slow); | 2822 __ bind(&slow); |
| 2751 | 2823 |
| 2752 // Postfix: Convert the operand to a number and store it as the result. | 2824 // Postfix: Convert the operand to a number and store it as the result. |
| 2753 if (is_postfix) { | 2825 if (is_postfix) { |
| 2754 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2); | 2826 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2); |
| 2755 __ CallStub(&stub); | 2827 __ CallStub(&stub); |
| 2756 // Store to result (on the stack). | 2828 // Store to result (on the stack). |
| 2757 __ str(r0, MemOperand(sp, target.size() * kPointerSize)); | 2829 __ str(r0, frame_->Element(target.size())); |
| 2758 } | 2830 } |
| 2759 | 2831 |
| 2760 // Compute the new value by calling the right JavaScript native. | 2832 // Compute the new value by calling the right JavaScript native. |
| 2761 if (is_increment) { | 2833 if (is_increment) { |
| 2762 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1); | 2834 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1); |
| 2763 __ CallStub(&stub); | 2835 __ CallStub(&stub); |
| 2764 } else { | 2836 } else { |
| 2765 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1); | 2837 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1); |
| 2766 __ CallStub(&stub); | 2838 __ CallStub(&stub); |
| 2767 } | 2839 } |
| 2768 | 2840 |
| 2769 // Store the new value in the target if not const. | 2841 // Store the new value in the target if not const. |
| 2770 __ bind(&exit); | 2842 __ bind(&exit); |
| 2771 __ push(r0); | 2843 frame_->Push(r0); |
| 2772 if (!is_const) target.SetValue(NOT_CONST_INIT); | 2844 if (!is_const) target.SetValue(NOT_CONST_INIT); |
| 2773 } | 2845 } |
| 2774 | 2846 |
| 2775 // Postfix: Discard the new value and use the old. | 2847 // Postfix: Discard the new value and use the old. |
| 2776 if (is_postfix) __ pop(r0); | 2848 if (is_postfix) frame_->Pop(r0); |
| 2777 } | 2849 } |
| 2778 | 2850 |
| 2779 | 2851 |
| 2780 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 2852 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 2781 Comment cmnt(masm_, "[ BinaryOperation"); | 2853 Comment cmnt(masm_, "[ BinaryOperation"); |
| 2782 Token::Value op = node->op(); | 2854 Token::Value op = node->op(); |
| 2783 | 2855 |
| 2784 // According to ECMA-262 section 11.11, page 58, the binary logical | 2856 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 2785 // operators must yield the result of one of the two expressions | 2857 // operators must yield the result of one of the two expressions |
| 2786 // before any ToBoolean() conversions. This means that the value | 2858 // before any ToBoolean() conversions. This means that the value |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2807 __ bind(&is_true); | 2879 __ bind(&is_true); |
| 2808 LoadCondition(node->right(), | 2880 LoadCondition(node->right(), |
| 2809 NOT_INSIDE_TYPEOF, | 2881 NOT_INSIDE_TYPEOF, |
| 2810 true_target(), | 2882 true_target(), |
| 2811 false_target(), | 2883 false_target(), |
| 2812 false); | 2884 false); |
| 2813 | 2885 |
| 2814 } else { | 2886 } else { |
| 2815 Label pop_and_continue, exit; | 2887 Label pop_and_continue, exit; |
| 2816 | 2888 |
| 2817 __ ldr(r0, MemOperand(sp, 0)); // dup the stack top | 2889 __ ldr(r0, frame_->Top()); // dup the stack top |
| 2818 __ push(r0); | 2890 frame_->Push(r0); |
| 2819 // Avoid popping the result if it converts to 'false' using the | 2891 // Avoid popping the result if it converts to 'false' using the |
| 2820 // standard ToBoolean() conversion as described in ECMA-262, | 2892 // standard ToBoolean() conversion as described in ECMA-262, |
| 2821 // section 9.2, page 30. | 2893 // section 9.2, page 30. |
| 2822 ToBoolean(&pop_and_continue, &exit); | 2894 ToBoolean(&pop_and_continue, &exit); |
| 2823 Branch(false, &exit); | 2895 Branch(false, &exit); |
| 2824 | 2896 |
| 2825 // Pop the result of evaluating the first part. | 2897 // Pop the result of evaluating the first part. |
| 2826 __ bind(&pop_and_continue); | 2898 __ bind(&pop_and_continue); |
| 2827 __ pop(r0); | 2899 frame_->Pop(r0); |
| 2828 | 2900 |
| 2829 // Evaluate right side expression. | 2901 // Evaluate right side expression. |
| 2830 __ bind(&is_true); | 2902 __ bind(&is_true); |
| 2831 Load(node->right()); | 2903 Load(node->right()); |
| 2832 | 2904 |
| 2833 // Exit (always with a materialized value). | 2905 // Exit (always with a materialized value). |
| 2834 __ bind(&exit); | 2906 __ bind(&exit); |
| 2835 } | 2907 } |
| 2836 | 2908 |
| 2837 } else if (op == Token::OR) { | 2909 } else if (op == Token::OR) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2848 __ bind(&is_false); | 2920 __ bind(&is_false); |
| 2849 LoadCondition(node->right(), | 2921 LoadCondition(node->right(), |
| 2850 NOT_INSIDE_TYPEOF, | 2922 NOT_INSIDE_TYPEOF, |
| 2851 true_target(), | 2923 true_target(), |
| 2852 false_target(), | 2924 false_target(), |
| 2853 false); | 2925 false); |
| 2854 | 2926 |
| 2855 } else { | 2927 } else { |
| 2856 Label pop_and_continue, exit; | 2928 Label pop_and_continue, exit; |
| 2857 | 2929 |
| 2858 __ ldr(r0, MemOperand(sp, 0)); | 2930 __ ldr(r0, frame_->Top()); |
| 2859 __ push(r0); | 2931 frame_->Push(r0); |
| 2860 // Avoid popping the result if it converts to 'true' using the | 2932 // Avoid popping the result if it converts to 'true' using the |
| 2861 // standard ToBoolean() conversion as described in ECMA-262, | 2933 // standard ToBoolean() conversion as described in ECMA-262, |
| 2862 // section 9.2, page 30. | 2934 // section 9.2, page 30. |
| 2863 ToBoolean(&exit, &pop_and_continue); | 2935 ToBoolean(&exit, &pop_and_continue); |
| 2864 Branch(true, &exit); | 2936 Branch(true, &exit); |
| 2865 | 2937 |
| 2866 // Pop the result of evaluating the first part. | 2938 // Pop the result of evaluating the first part. |
| 2867 __ bind(&pop_and_continue); | 2939 __ bind(&pop_and_continue); |
| 2868 __ pop(r0); | 2940 frame_->Pop(r0); |
| 2869 | 2941 |
| 2870 // Evaluate right side expression. | 2942 // Evaluate right side expression. |
| 2871 __ bind(&is_false); | 2943 __ bind(&is_false); |
| 2872 Load(node->right()); | 2944 Load(node->right()); |
| 2873 | 2945 |
| 2874 // Exit (always with a materialized value). | 2946 // Exit (always with a materialized value). |
| 2875 __ bind(&exit); | 2947 __ bind(&exit); |
| 2876 } | 2948 } |
| 2877 | 2949 |
| 2878 } else { | 2950 } else { |
| 2879 // Optimize for the case where (at least) one of the expressions | 2951 // Optimize for the case where (at least) one of the expressions |
| 2880 // is a literal small integer. | 2952 // is a literal small integer. |
| 2881 Literal* lliteral = node->left()->AsLiteral(); | 2953 Literal* lliteral = node->left()->AsLiteral(); |
| 2882 Literal* rliteral = node->right()->AsLiteral(); | 2954 Literal* rliteral = node->right()->AsLiteral(); |
| 2883 | 2955 |
| 2884 if (rliteral != NULL && rliteral->handle()->IsSmi()) { | 2956 if (rliteral != NULL && rliteral->handle()->IsSmi()) { |
| 2885 Load(node->left()); | 2957 Load(node->left()); |
| 2886 SmiOperation(node->op(), rliteral->handle(), false); | 2958 SmiOperation(node->op(), rliteral->handle(), false); |
| 2887 | 2959 |
| 2888 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { | 2960 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { |
| 2889 Load(node->right()); | 2961 Load(node->right()); |
| 2890 SmiOperation(node->op(), lliteral->handle(), true); | 2962 SmiOperation(node->op(), lliteral->handle(), true); |
| 2891 | 2963 |
| 2892 } else { | 2964 } else { |
| 2893 Load(node->left()); | 2965 Load(node->left()); |
| 2894 Load(node->right()); | 2966 Load(node->right()); |
| 2895 GenericBinaryOperation(node->op()); | 2967 GenericBinaryOperation(node->op()); |
| 2896 } | 2968 } |
| 2897 __ push(r0); | 2969 frame_->Push(r0); |
| 2898 } | 2970 } |
| 2899 } | 2971 } |
| 2900 | 2972 |
| 2901 | 2973 |
| 2902 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 2974 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 2903 __ ldr(r0, FunctionOperand()); | 2975 __ ldr(r0, frame_->Function()); |
| 2904 __ push(r0); | 2976 frame_->Push(r0); |
| 2905 } | 2977 } |
| 2906 | 2978 |
| 2907 | 2979 |
| 2908 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 2980 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 2909 Comment cmnt(masm_, "[ CompareOperation"); | 2981 Comment cmnt(masm_, "[ CompareOperation"); |
| 2910 | 2982 |
| 2911 // Get the expressions from the node. | 2983 // Get the expressions from the node. |
| 2912 Expression* left = node->left(); | 2984 Expression* left = node->left(); |
| 2913 Expression* right = node->right(); | 2985 Expression* right = node->right(); |
| 2914 Token::Value op = node->op(); | 2986 Token::Value op = node->op(); |
| 2915 | 2987 |
| 2916 // NOTE: To make null checks efficient, we check if either left or | 2988 // To make null checks efficient, we check if either left or right is the |
| 2917 // right is the literal 'null'. If so, we optimize the code by | 2989 // literal 'null'. If so, we optimize the code by inlining a null check |
| 2918 // inlining a null check instead of calling the (very) general | 2990 // instead of calling the (very) general runtime routine for checking |
| 2919 // runtime routine for checking equality. | 2991 // equality. |
| 2920 | |
| 2921 if (op == Token::EQ || op == Token::EQ_STRICT) { | 2992 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 2922 bool left_is_null = | 2993 bool left_is_null = |
| 2923 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 2994 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 2924 bool right_is_null = | 2995 bool right_is_null = |
| 2925 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 2996 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 2926 // The 'null' value is only equal to 'null' or 'undefined'. | 2997 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 2927 if (left_is_null || right_is_null) { | 2998 if (left_is_null || right_is_null) { |
| 2928 Load(left_is_null ? right : left); | 2999 Load(left_is_null ? right : left); |
| 2929 Label exit, undetectable; | 3000 frame_->Pop(r0); |
| 2930 __ pop(r0); | |
| 2931 __ cmp(r0, Operand(Factory::null_value())); | 3001 __ cmp(r0, Operand(Factory::null_value())); |
| 2932 | 3002 |
| 2933 // The 'null' value is only equal to 'undefined' if using | 3003 // The 'null' value is only equal to 'undefined' if using non-strict |
| 2934 // non-strict comparisons. | 3004 // comparisons. |
| 2935 if (op != Token::EQ_STRICT) { | 3005 if (op != Token::EQ_STRICT) { |
| 2936 __ b(eq, &exit); | 3006 __ b(eq, true_target()); |
| 3007 |
| 2937 __ cmp(r0, Operand(Factory::undefined_value())); | 3008 __ cmp(r0, Operand(Factory::undefined_value())); |
| 3009 __ b(eq, true_target()); |
| 2938 | 3010 |
| 2939 // NOTE: it can be undetectable object. | |
| 2940 __ b(eq, &exit); | |
| 2941 __ tst(r0, Operand(kSmiTagMask)); | 3011 __ tst(r0, Operand(kSmiTagMask)); |
| 3012 __ b(eq, false_target()); |
| 2942 | 3013 |
| 2943 __ b(ne, &undetectable); | 3014 // It can be an undetectable object. |
| 2944 __ b(false_target()); | 3015 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2945 | 3016 __ ldrb(r0, FieldMemOperand(r0, Map::kBitFieldOffset)); |
| 2946 __ bind(&undetectable); | 3017 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable)); |
| 2947 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3018 __ cmp(r0, Operand(1 << Map::kIsUndetectable)); |
| 2948 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | |
| 2949 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | |
| 2950 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | |
| 2951 } | 3019 } |
| 2952 | 3020 |
| 2953 __ bind(&exit); | |
| 2954 | |
| 2955 cc_reg_ = eq; | 3021 cc_reg_ = eq; |
| 2956 return; | 3022 return; |
| 2957 } | 3023 } |
| 2958 } | 3024 } |
| 2959 | 3025 |
| 2960 | 3026 // To make typeof testing for natives implemented in JavaScript really |
| 2961 // NOTE: To make typeof testing for natives implemented in | 3027 // efficient, we generate special code for expressions of the form: |
| 2962 // JavaScript really efficient, we generate special code for | 3028 // 'typeof <expression> == <string>'. |
| 2963 // expressions of the form: 'typeof <expression> == <string>'. | |
| 2964 | |
| 2965 UnaryOperation* operation = left->AsUnaryOperation(); | 3029 UnaryOperation* operation = left->AsUnaryOperation(); |
| 2966 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3030 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 2967 (operation != NULL && operation->op() == Token::TYPEOF) && | 3031 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 2968 (right->AsLiteral() != NULL && | 3032 (right->AsLiteral() != NULL && |
| 2969 right->AsLiteral()->handle()->IsString())) { | 3033 right->AsLiteral()->handle()->IsString())) { |
| 2970 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3034 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 2971 | 3035 |
| 2972 // Load the operand, move it to register r1. | 3036 // Load the operand, move it to register r1. |
| 2973 LoadTypeofExpression(operation->expression()); | 3037 LoadTypeofExpression(operation->expression()); |
| 2974 __ pop(r1); | 3038 frame_->Pop(r1); |
| 2975 | 3039 |
| 2976 if (check->Equals(Heap::number_symbol())) { | 3040 if (check->Equals(Heap::number_symbol())) { |
| 2977 __ tst(r1, Operand(kSmiTagMask)); | 3041 __ tst(r1, Operand(kSmiTagMask)); |
| 2978 __ b(eq, true_target()); | 3042 __ b(eq, true_target()); |
| 2979 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3043 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 2980 __ cmp(r1, Operand(Factory::heap_number_map())); | 3044 __ cmp(r1, Operand(Factory::heap_number_map())); |
| 2981 cc_reg_ = eq; | 3045 cc_reg_ = eq; |
| 2982 | 3046 |
| 2983 } else if (check->Equals(Heap::string_symbol())) { | 3047 } else if (check->Equals(Heap::string_symbol())) { |
| 2984 __ tst(r1, Operand(kSmiTagMask)); | 3048 __ tst(r1, Operand(kSmiTagMask)); |
| 2985 __ b(eq, false_target()); | 3049 __ b(eq, false_target()); |
| 2986 | 3050 |
| 2987 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3051 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 2988 | 3052 |
| 2989 // NOTE: it might be an undetectable string object | 3053 // It can be an undetectable string object. |
| 2990 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 3054 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 2991 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 3055 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); |
| 2992 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 3056 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); |
| 2993 __ b(eq, false_target()); | 3057 __ b(eq, false_target()); |
| 2994 | 3058 |
| 2995 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3059 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 2996 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE)); | 3060 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE)); |
| 2997 cc_reg_ = lt; | 3061 cc_reg_ = lt; |
| 2998 | 3062 |
| 2999 } else if (check->Equals(Heap::boolean_symbol())) { | 3063 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3000 __ cmp(r1, Operand(Factory::true_value())); | 3064 __ cmp(r1, Operand(Factory::true_value())); |
| 3001 __ b(eq, true_target()); | 3065 __ b(eq, true_target()); |
| 3002 __ cmp(r1, Operand(Factory::false_value())); | 3066 __ cmp(r1, Operand(Factory::false_value())); |
| 3003 cc_reg_ = eq; | 3067 cc_reg_ = eq; |
| 3004 | 3068 |
| 3005 } else if (check->Equals(Heap::undefined_symbol())) { | 3069 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3006 __ cmp(r1, Operand(Factory::undefined_value())); | 3070 __ cmp(r1, Operand(Factory::undefined_value())); |
| 3007 __ b(eq, true_target()); | 3071 __ b(eq, true_target()); |
| 3008 | 3072 |
| 3009 __ tst(r1, Operand(kSmiTagMask)); | 3073 __ tst(r1, Operand(kSmiTagMask)); |
| 3010 __ b(eq, false_target()); | 3074 __ b(eq, false_target()); |
| 3011 | 3075 |
| 3012 // NOTE: it can be undetectable object. | 3076 // It can be an undetectable object. |
| 3013 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3077 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3014 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 3078 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 3015 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 3079 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); |
| 3016 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 3080 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); |
| 3017 | 3081 |
| 3018 cc_reg_ = eq; | 3082 cc_reg_ = eq; |
| 3019 | 3083 |
| 3020 } else if (check->Equals(Heap::function_symbol())) { | 3084 } else if (check->Equals(Heap::function_symbol())) { |
| 3021 __ tst(r1, Operand(kSmiTagMask)); | 3085 __ tst(r1, Operand(kSmiTagMask)); |
| 3022 __ b(eq, false_target()); | 3086 __ b(eq, false_target()); |
| 3023 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3087 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3024 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3088 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 3025 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); | 3089 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); |
| 3026 cc_reg_ = eq; | 3090 cc_reg_ = eq; |
| 3027 | 3091 |
| 3028 } else if (check->Equals(Heap::object_symbol())) { | 3092 } else if (check->Equals(Heap::object_symbol())) { |
| 3029 __ tst(r1, Operand(kSmiTagMask)); | 3093 __ tst(r1, Operand(kSmiTagMask)); |
| 3030 __ b(eq, false_target()); | 3094 __ b(eq, false_target()); |
| 3031 | 3095 |
| 3032 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3096 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3033 __ cmp(r1, Operand(Factory::null_value())); | 3097 __ cmp(r1, Operand(Factory::null_value())); |
| 3034 __ b(eq, true_target()); | 3098 __ b(eq, true_target()); |
| 3035 | 3099 |
| 3036 // NOTE: it might be an undetectable object. | 3100 // It can be an undetectable object. |
| 3037 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); | 3101 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); |
| 3038 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); | 3102 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); |
| 3039 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); | 3103 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); |
| 3040 __ b(eq, false_target()); | 3104 __ b(eq, false_target()); |
| 3041 | 3105 |
| 3042 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 3106 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 3043 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); | 3107 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); |
| 3044 __ b(lt, false_target()); | 3108 __ b(lt, false_target()); |
| 3045 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); | 3109 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); |
| 3046 cc_reg_ = le; | 3110 cc_reg_ = le; |
| 3047 | 3111 |
| 3048 } else { | 3112 } else { |
| 3049 // Uncommon case: Typeof testing against a string literal that | 3113 // Uncommon case: typeof testing against a string literal that is |
| 3050 // is never returned from the typeof operator. | 3114 // never returned from the typeof operator. |
| 3051 __ b(false_target()); | 3115 __ b(false_target()); |
| 3052 } | 3116 } |
| 3053 return; | 3117 return; |
| 3054 } | 3118 } |
| 3055 | 3119 |
| 3056 Load(left); | 3120 Load(left); |
| 3057 Load(right); | 3121 Load(right); |
| 3058 switch (op) { | 3122 switch (op) { |
| 3059 case Token::EQ: | 3123 case Token::EQ: |
| 3060 Comparison(eq, false); | 3124 Comparison(eq, false); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3076 Comparison(ge); | 3140 Comparison(ge); |
| 3077 break; | 3141 break; |
| 3078 | 3142 |
| 3079 case Token::EQ_STRICT: | 3143 case Token::EQ_STRICT: |
| 3080 Comparison(eq, true); | 3144 Comparison(eq, true); |
| 3081 break; | 3145 break; |
| 3082 | 3146 |
| 3083 case Token::IN: | 3147 case Token::IN: |
| 3084 __ mov(r0, Operand(1)); // not counting receiver | 3148 __ mov(r0, Operand(1)); // not counting receiver |
| 3085 __ InvokeBuiltin(Builtins::IN, CALL_JS); | 3149 __ InvokeBuiltin(Builtins::IN, CALL_JS); |
| 3086 __ push(r0); | 3150 frame_->Push(r0); |
| 3087 break; | 3151 break; |
| 3088 | 3152 |
| 3089 case Token::INSTANCEOF: | 3153 case Token::INSTANCEOF: |
| 3090 __ mov(r0, Operand(1)); // not counting receiver | 3154 __ mov(r0, Operand(1)); // not counting receiver |
| 3091 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS); | 3155 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS); |
| 3092 __ tst(r0, Operand(r0)); | 3156 __ tst(r0, Operand(r0)); |
| 3093 cc_reg_ = eq; | 3157 cc_reg_ = eq; |
| 3094 break; | 3158 break; |
| 3095 | 3159 |
| 3096 default: | 3160 default: |
| 3097 UNREACHABLE(); | 3161 UNREACHABLE(); |
| 3098 } | 3162 } |
| 3099 } | 3163 } |
| 3100 | 3164 |
| 3101 | 3165 |
| 3102 void CodeGenerator::RecordStatementPosition(Node* node) { | 3166 void CodeGenerator::RecordStatementPosition(Node* node) { |
| 3103 if (FLAG_debug_info) { | 3167 if (FLAG_debug_info) { |
| 3104 int statement_pos = node->statement_pos(); | 3168 int statement_pos = node->statement_pos(); |
| 3105 if (statement_pos == RelocInfo::kNoPosition) return; | 3169 if (statement_pos == RelocInfo::kNoPosition) return; |
| 3106 __ RecordStatementPosition(statement_pos); | 3170 __ RecordStatementPosition(statement_pos); |
| 3107 } | 3171 } |
| 3108 } | 3172 } |
| 3109 | 3173 |
| 3110 | 3174 |
| 3111 void CodeGenerator::EnterJSFrame() { | |
| 3112 #if defined(DEBUG) | |
| 3113 { Label done, fail; | |
| 3114 __ tst(r1, Operand(kSmiTagMask)); | |
| 3115 __ b(eq, &fail); | |
| 3116 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
| 3117 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | |
| 3118 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); | |
| 3119 __ b(eq, &done); | |
| 3120 __ bind(&fail); | |
| 3121 __ stop("CodeGenerator::EnterJSFrame - r1 not a function"); | |
| 3122 __ bind(&done); | |
| 3123 } | |
| 3124 #endif // DEBUG | |
| 3125 | |
| 3126 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); | |
| 3127 __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. | |
| 3128 } | |
| 3129 | |
| 3130 | |
| 3131 void CodeGenerator::ExitJSFrame() { | |
| 3132 // Drop the execution stack down to the frame pointer and restore the caller | |
| 3133 // frame pointer and return address. | |
| 3134 __ mov(sp, fp); | |
| 3135 __ ldm(ia_w, sp, fp.bit() | lr.bit()); | |
| 3136 } | |
| 3137 | |
| 3138 | |
| 3139 #undef __ | 3175 #undef __ |
| 3140 #define __ masm-> | 3176 #define __ masm-> |
| 3141 | 3177 |
| 3142 Handle<String> Reference::GetName() { | 3178 Handle<String> Reference::GetName() { |
| 3143 ASSERT(type_ == NAMED); | 3179 ASSERT(type_ == NAMED); |
| 3144 Property* property = expression_->AsProperty(); | 3180 Property* property = expression_->AsProperty(); |
| 3145 if (property == NULL) { | 3181 if (property == NULL) { |
| 3146 // Global variable reference treated as a named property reference. | 3182 // Global variable reference treated as a named property reference. |
| 3147 VariableProxy* proxy = expression_->AsVariableProxy(); | 3183 VariableProxy* proxy = expression_->AsVariableProxy(); |
| 3148 ASSERT(proxy->AsVariable() != NULL); | 3184 ASSERT(proxy->AsVariable() != NULL); |
| 3149 ASSERT(proxy->AsVariable()->is_global()); | 3185 ASSERT(proxy->AsVariable()->is_global()); |
| 3150 return proxy->name(); | 3186 return proxy->name(); |
| 3151 } else { | 3187 } else { |
| 3152 Literal* raw_name = property->key()->AsLiteral(); | 3188 Literal* raw_name = property->key()->AsLiteral(); |
| 3153 ASSERT(raw_name != NULL); | 3189 ASSERT(raw_name != NULL); |
| 3154 return Handle<String>(String::cast(*raw_name->handle())); | 3190 return Handle<String>(String::cast(*raw_name->handle())); |
| 3155 } | 3191 } |
| 3156 } | 3192 } |
| 3157 | 3193 |
| 3158 | 3194 |
| 3159 void Reference::GetValue(TypeofState typeof_state) { | 3195 void Reference::GetValue(TypeofState typeof_state) { |
| 3160 ASSERT(!is_illegal()); | 3196 ASSERT(!is_illegal()); |
| 3161 ASSERT(!cgen_->has_cc()); | 3197 ASSERT(!cgen_->has_cc()); |
| 3162 MacroAssembler* masm = cgen_->masm(); | 3198 MacroAssembler* masm = cgen_->masm(); |
| 3199 VirtualFrame* frame = cgen_->frame(); |
| 3163 Property* property = expression_->AsProperty(); | 3200 Property* property = expression_->AsProperty(); |
| 3164 if (property != NULL) { | 3201 if (property != NULL) { |
| 3165 __ RecordPosition(property->position()); | 3202 __ RecordPosition(property->position()); |
| 3166 } | 3203 } |
| 3167 | 3204 |
| 3168 switch (type_) { | 3205 switch (type_) { |
| 3169 case SLOT: { | 3206 case SLOT: { |
| 3170 Comment cmnt(masm, "[ Load from Slot"); | 3207 Comment cmnt(masm, "[ Load from Slot"); |
| 3171 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 3208 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 3172 ASSERT(slot != NULL); | 3209 ASSERT(slot != NULL); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3186 __ mov(r2, Operand(name)); | 3223 __ mov(r2, Operand(name)); |
| 3187 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3224 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 3188 | 3225 |
| 3189 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3226 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3190 if (var != NULL) { | 3227 if (var != NULL) { |
| 3191 ASSERT(var->is_global()); | 3228 ASSERT(var->is_global()); |
| 3192 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 3229 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 3193 } else { | 3230 } else { |
| 3194 __ Call(ic, RelocInfo::CODE_TARGET); | 3231 __ Call(ic, RelocInfo::CODE_TARGET); |
| 3195 } | 3232 } |
| 3196 __ push(r0); | 3233 frame->Push(r0); |
| 3197 break; | 3234 break; |
| 3198 } | 3235 } |
| 3199 | 3236 |
| 3200 case KEYED: { | 3237 case KEYED: { |
| 3201 // TODO(1241834): Make sure that this it is safe to ignore the | 3238 // TODO(1241834): Make sure that this it is safe to ignore the |
| 3202 // distinction between expressions in a typeof and not in a typeof. | 3239 // distinction between expressions in a typeof and not in a typeof. |
| 3203 Comment cmnt(masm, "[ Load from keyed Property"); | 3240 Comment cmnt(masm, "[ Load from keyed Property"); |
| 3204 ASSERT(property != NULL); | 3241 ASSERT(property != NULL); |
| 3205 // TODO(1224671): Implement inline caching for keyed loads as on ia32. | 3242 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 3206 GetPropertyStub stub; | 3243 |
| 3207 __ CallStub(&stub); | 3244 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3208 __ push(r0); | 3245 if (var != NULL) { |
| 3246 ASSERT(var->is_global()); |
| 3247 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 3248 } else { |
| 3249 __ Call(ic, RelocInfo::CODE_TARGET); |
| 3250 } |
| 3251 frame->Push(r0); |
| 3209 break; | 3252 break; |
| 3210 } | 3253 } |
| 3211 | 3254 |
| 3212 default: | 3255 default: |
| 3213 UNREACHABLE(); | 3256 UNREACHABLE(); |
| 3214 } | 3257 } |
| 3215 } | 3258 } |
| 3216 | 3259 |
| 3217 | 3260 |
| 3218 void Reference::SetValue(InitState init_state) { | 3261 void Reference::SetValue(InitState init_state) { |
| 3219 ASSERT(!is_illegal()); | 3262 ASSERT(!is_illegal()); |
| 3220 ASSERT(!cgen_->has_cc()); | 3263 ASSERT(!cgen_->has_cc()); |
| 3221 MacroAssembler* masm = cgen_->masm(); | 3264 MacroAssembler* masm = cgen_->masm(); |
| 3265 VirtualFrame* frame = cgen_->frame(); |
| 3222 Property* property = expression_->AsProperty(); | 3266 Property* property = expression_->AsProperty(); |
| 3223 if (property != NULL) { | 3267 if (property != NULL) { |
| 3224 __ RecordPosition(property->position()); | 3268 __ RecordPosition(property->position()); |
| 3225 } | 3269 } |
| 3226 | 3270 |
| 3227 switch (type_) { | 3271 switch (type_) { |
| 3228 case SLOT: { | 3272 case SLOT: { |
| 3229 Comment cmnt(masm, "[ Store to Slot"); | 3273 Comment cmnt(masm, "[ Store to Slot"); |
| 3230 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 3274 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 3231 ASSERT(slot != NULL); | 3275 ASSERT(slot != NULL); |
| 3232 if (slot->type() == Slot::LOOKUP) { | 3276 if (slot->type() == Slot::LOOKUP) { |
| 3233 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 3277 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 3234 | 3278 |
| 3235 // For now, just do a runtime call. | 3279 // For now, just do a runtime call. |
| 3236 __ push(cp); | 3280 frame->Push(cp); |
| 3237 __ mov(r0, Operand(slot->var()->name())); | 3281 __ mov(r0, Operand(slot->var()->name())); |
| 3238 __ push(r0); | 3282 frame->Push(r0); |
| 3239 | 3283 |
| 3240 if (init_state == CONST_INIT) { | 3284 if (init_state == CONST_INIT) { |
| 3241 // Same as the case for a normal store, but ignores attribute | 3285 // Same as the case for a normal store, but ignores attribute |
| 3242 // (e.g. READ_ONLY) of context slot so that we can initialize | 3286 // (e.g. READ_ONLY) of context slot so that we can initialize |
| 3243 // const properties (introduced via eval("const foo = (some | 3287 // const properties (introduced via eval("const foo = (some |
| 3244 // expr);")). Also, uses the current function context instead of | 3288 // expr);")). Also, uses the current function context instead of |
| 3245 // the top context. | 3289 // the top context. |
| 3246 // | 3290 // |
| 3247 // Note that we must declare the foo upon entry of eval(), via a | 3291 // Note that we must declare the foo upon entry of eval(), via a |
| 3248 // context slot declaration, but we cannot initialize it at the | 3292 // context slot declaration, but we cannot initialize it at the |
| 3249 // same time, because the const declaration may be at the end of | 3293 // same time, because the const declaration may be at the end of |
| 3250 // the eval code (sigh...) and the const variable may have been | 3294 // the eval code (sigh...) and the const variable may have been |
| 3251 // used before (where its value is 'undefined'). Thus, we can only | 3295 // used before (where its value is 'undefined'). Thus, we can only |
| 3252 // do the initialization when we actually encounter the expression | 3296 // do the initialization when we actually encounter the expression |
| 3253 // and when the expression operands are defined and valid, and | 3297 // and when the expression operands are defined and valid, and |
| 3254 // thus we need the split into 2 operations: declaration of the | 3298 // thus we need the split into 2 operations: declaration of the |
| 3255 // context slot followed by initialization. | 3299 // context slot followed by initialization. |
| 3256 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 3300 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 3257 } else { | 3301 } else { |
| 3258 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 3302 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
| 3259 } | 3303 } |
| 3260 // Storing a variable must keep the (new) value on the expression | 3304 // Storing a variable must keep the (new) value on the expression |
| 3261 // stack. This is necessary for compiling assignment expressions. | 3305 // stack. This is necessary for compiling assignment expressions. |
| 3262 __ push(r0); | 3306 frame->Push(r0); |
| 3263 | 3307 |
| 3264 } else { | 3308 } else { |
| 3265 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 3309 ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 3266 | 3310 |
| 3267 Label exit; | 3311 Label exit; |
| 3268 if (init_state == CONST_INIT) { | 3312 if (init_state == CONST_INIT) { |
| 3269 ASSERT(slot->var()->mode() == Variable::CONST); | 3313 ASSERT(slot->var()->mode() == Variable::CONST); |
| 3270 // Only the first const initialization must be executed (the slot | 3314 // Only the first const initialization must be executed (the slot |
| 3271 // still contains 'the hole' value). When the assignment is | 3315 // still contains 'the hole' value). When the assignment is |
| 3272 // executed, the code is identical to a normal store (see below). | 3316 // executed, the code is identical to a normal store (see below). |
| 3273 Comment cmnt(masm, "[ Init const"); | 3317 Comment cmnt(masm, "[ Init const"); |
| 3274 __ ldr(r2, cgen_->SlotOperand(slot, r2)); | 3318 __ ldr(r2, cgen_->SlotOperand(slot, r2)); |
| 3275 __ cmp(r2, Operand(Factory::the_hole_value())); | 3319 __ cmp(r2, Operand(Factory::the_hole_value())); |
| 3276 __ b(ne, &exit); | 3320 __ b(ne, &exit); |
| 3277 } | 3321 } |
| 3278 | 3322 |
| 3279 // We must execute the store. Storing a variable must keep the | 3323 // We must execute the store. Storing a variable must keep the |
| 3280 // (new) value on the stack. This is necessary for compiling | 3324 // (new) value on the stack. This is necessary for compiling |
| 3281 // assignment expressions. | 3325 // assignment expressions. |
| 3282 // | 3326 // |
| 3283 // Note: We will reach here even with slot->var()->mode() == | 3327 // Note: We will reach here even with slot->var()->mode() == |
| 3284 // Variable::CONST because of const declarations which will | 3328 // Variable::CONST because of const declarations which will |
| 3285 // initialize consts to 'the hole' value and by doing so, end up | 3329 // initialize consts to 'the hole' value and by doing so, end up |
| 3286 // calling this code. r2 may be loaded with context; used below in | 3330 // calling this code. r2 may be loaded with context; used below in |
| 3287 // RecordWrite. | 3331 // RecordWrite. |
| 3288 __ pop(r0); | 3332 frame->Pop(r0); |
| 3289 __ str(r0, cgen_->SlotOperand(slot, r2)); | 3333 __ str(r0, cgen_->SlotOperand(slot, r2)); |
| 3290 __ push(r0); | 3334 frame->Push(r0); |
| 3291 if (slot->type() == Slot::CONTEXT) { | 3335 if (slot->type() == Slot::CONTEXT) { |
| 3292 // Skip write barrier if the written value is a smi. | 3336 // Skip write barrier if the written value is a smi. |
| 3293 __ tst(r0, Operand(kSmiTagMask)); | 3337 __ tst(r0, Operand(kSmiTagMask)); |
| 3294 __ b(eq, &exit); | 3338 __ b(eq, &exit); |
| 3295 // r2 is loaded with context when calling SlotOperand above. | 3339 // r2 is loaded with context when calling SlotOperand above. |
| 3296 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 3340 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 3297 __ mov(r3, Operand(offset)); | 3341 __ mov(r3, Operand(offset)); |
| 3298 __ RecordWrite(r2, r3, r1); | 3342 __ RecordWrite(r2, r3, r1); |
| 3299 } | 3343 } |
| 3300 // If we definitely did not jump over the assignment, we do not need | 3344 // If we definitely did not jump over the assignment, we do not need |
| 3301 // to bind the exit label. Doing so can defeat peephole | 3345 // to bind the exit label. Doing so can defeat peephole |
| 3302 // optimization. | 3346 // optimization. |
| 3303 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { | 3347 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { |
| 3304 __ bind(&exit); | 3348 __ bind(&exit); |
| 3305 } | 3349 } |
| 3306 } | 3350 } |
| 3307 break; | 3351 break; |
| 3308 } | 3352 } |
| 3309 | 3353 |
| 3310 case NAMED: { | 3354 case NAMED: { |
| 3311 Comment cmnt(masm, "[ Store to named Property"); | 3355 Comment cmnt(masm, "[ Store to named Property"); |
| 3312 // Call the appropriate IC code. | 3356 // Call the appropriate IC code. |
| 3313 __ pop(r0); // value | 3357 frame->Pop(r0); // value |
| 3314 // Setup the name register. | 3358 // Setup the name register. |
| 3315 Handle<String> name(GetName()); | 3359 Handle<String> name(GetName()); |
| 3316 __ mov(r2, Operand(name)); | 3360 __ mov(r2, Operand(name)); |
| 3317 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3361 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 3318 __ Call(ic, RelocInfo::CODE_TARGET); | 3362 __ Call(ic, RelocInfo::CODE_TARGET); |
| 3319 __ push(r0); | 3363 frame->Push(r0); |
| 3320 break; | 3364 break; |
| 3321 } | 3365 } |
| 3322 | 3366 |
| 3323 case KEYED: { | 3367 case KEYED: { |
| 3324 Comment cmnt(masm, "[ Store to keyed Property"); | 3368 Comment cmnt(masm, "[ Store to keyed Property"); |
| 3325 Property* property = expression_->AsProperty(); | 3369 Property* property = expression_->AsProperty(); |
| 3326 ASSERT(property != NULL); | 3370 ASSERT(property != NULL); |
| 3327 __ RecordPosition(property->position()); | 3371 __ RecordPosition(property->position()); |
| 3328 __ pop(r0); // value | 3372 |
| 3329 SetPropertyStub stub; | 3373 // Call IC code. |
| 3330 __ CallStub(&stub); | 3374 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 3331 __ push(r0); | 3375 // TODO(1222589): Make the IC grab the values from the stack. |
| 3376 frame->Pop(r0); // value |
| 3377 __ Call(ic, RelocInfo::CODE_TARGET); |
| 3378 frame->Push(r0); |
| 3332 break; | 3379 break; |
| 3333 } | 3380 } |
| 3334 | 3381 |
| 3335 default: | 3382 default: |
| 3336 UNREACHABLE(); | 3383 UNREACHABLE(); |
| 3337 } | 3384 } |
| 3338 } | 3385 } |
| 3339 | 3386 |
| 3340 | 3387 |
| 3341 void GetPropertyStub::Generate(MacroAssembler* masm) { | 3388 void GetPropertyStub::Generate(MacroAssembler* masm) { |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3806 | 3853 |
| 3807 // Set pending exception and r0 to out of memory exception. | 3854 // Set pending exception and r0 to out of memory exception. |
| 3808 Failure* out_of_memory = Failure::OutOfMemoryException(); | 3855 Failure* out_of_memory = Failure::OutOfMemoryException(); |
| 3809 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); | 3856 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); |
| 3810 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address))); | 3857 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address))); |
| 3811 __ str(r0, MemOperand(r2)); | 3858 __ str(r0, MemOperand(r2)); |
| 3812 | 3859 |
| 3813 // Restore the stack to the address of the ENTRY handler | 3860 // Restore the stack to the address of the ENTRY handler |
| 3814 __ mov(sp, Operand(r3)); | 3861 __ mov(sp, Operand(r3)); |
| 3815 | 3862 |
| 3816 // restore parameter- and frame-pointer and pop state. | 3863 // Stack layout at this point. See also PushTryHandler |
| 3817 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit()); | 3864 // r3, sp -> next handler |
| 3865 // state (ENTRY) |
| 3866 // pp |
| 3867 // fp |
| 3868 // lr |
| 3869 |
| 3870 // Discard ENTRY state (r2 is not used), and restore parameter- |
| 3871 // and frame-pointer and pop state. |
| 3872 __ ldm(ia_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit()); |
| 3818 // Before returning we restore the context from the frame pointer if not NULL. | 3873 // Before returning we restore the context from the frame pointer if not NULL. |
| 3819 // The frame pointer is NULL in the exception handler of a JS entry frame. | 3874 // The frame pointer is NULL in the exception handler of a JS entry frame. |
| 3820 __ cmp(fp, Operand(0)); | 3875 __ cmp(fp, Operand(0)); |
| 3821 // Set cp to NULL if fp is NULL. | 3876 // Set cp to NULL if fp is NULL. |
| 3822 __ mov(cp, Operand(0), LeaveCC, eq); | 3877 __ mov(cp, Operand(0), LeaveCC, eq); |
| 3823 // Restore cp otherwise. | 3878 // Restore cp otherwise. |
| 3824 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); | 3879 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
| 3825 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc)); | 3880 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc)); |
| 3826 __ pop(pc); | 3881 __ pop(pc); |
| 3827 } | 3882 } |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4037 | 4092 |
| 4038 // Call a faked try-block that does the invoke. | 4093 // Call a faked try-block that does the invoke. |
| 4039 __ bl(&invoke); | 4094 __ bl(&invoke); |
| 4040 | 4095 |
| 4041 // Caught exception: Store result (exception) in the pending | 4096 // Caught exception: Store result (exception) in the pending |
| 4042 // exception field in the JSEnv and return a failure sentinel. | 4097 // exception field in the JSEnv and return a failure sentinel. |
| 4043 // Coming in here the fp will be invalid because the PushTryHandler below | 4098 // Coming in here the fp will be invalid because the PushTryHandler below |
| 4044 // sets it to 0 to signal the existence of the JSEntry frame. | 4099 // sets it to 0 to signal the existence of the JSEntry frame. |
| 4045 __ mov(ip, Operand(Top::pending_exception_address())); | 4100 __ mov(ip, Operand(Top::pending_exception_address())); |
| 4046 __ str(r0, MemOperand(ip)); | 4101 __ str(r0, MemOperand(ip)); |
| 4047 __ mov(r0, Operand(Handle<Failure>(Failure::Exception()))); | 4102 __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception()))); |
| 4048 __ b(&exit); | 4103 __ b(&exit); |
| 4049 | 4104 |
| 4050 // Invoke: Link this frame into the handler chain. | 4105 // Invoke: Link this frame into the handler chain. |
| 4051 __ bind(&invoke); | 4106 __ bind(&invoke); |
| 4052 // Must preserve r0-r4, r5-r7 are available. | 4107 // Must preserve r0-r4, r5-r7 are available. |
| 4053 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); | 4108 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); |
| 4054 // If an exception not caught by another handler occurs, this handler returns | 4109 // If an exception not caught by another handler occurs, this handler returns |
| 4055 // control to the code after the bl(&invoke) above, which restores all | 4110 // control to the code after the bl(&invoke) above, which restores all |
| 4056 // kCalleeSaved registers (including cp, pp and fp) to their saved values | 4111 // kCalleeSaved registers (including cp, pp and fp) to their saved values |
| 4057 // before returning a failure to C. | 4112 // before returning a failure to C. |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4222 __ b(ne, &slow); | 4277 __ b(ne, &slow); |
| 4223 | 4278 |
| 4224 // Fast-case: Invoke the function now. | 4279 // Fast-case: Invoke the function now. |
| 4225 // r1: pushed function | 4280 // r1: pushed function |
| 4226 ParameterCount actual(argc_); | 4281 ParameterCount actual(argc_); |
| 4227 __ InvokeFunction(r1, actual, JUMP_FUNCTION); | 4282 __ InvokeFunction(r1, actual, JUMP_FUNCTION); |
| 4228 | 4283 |
| 4229 // Slow-case: Non-function called. | 4284 // Slow-case: Non-function called. |
| 4230 __ bind(&slow); | 4285 __ bind(&slow); |
| 4231 __ mov(r0, Operand(argc_)); // Setup the number of arguments. | 4286 __ mov(r0, Operand(argc_)); // Setup the number of arguments. |
| 4232 __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS); | 4287 __ mov(r2, Operand(0)); |
| 4288 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 4289 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
| 4290 RelocInfo::CODE_TARGET); |
| 4233 } | 4291 } |
| 4234 | 4292 |
| 4235 | 4293 |
| 4236 #undef __ | 4294 #undef __ |
| 4237 | 4295 |
| 4238 } } // namespace v8::internal | 4296 } } // namespace v8::internal |
| OLD | NEW |