blob: 951209d964c43aabb9c84f4e8eb24fac95d3cd9e [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "accessors.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010031#include "ast.h"
32#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "execution.h"
34#include "factory.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000035#include "list-inl.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010036#include "safepoint-table.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037#include "scopeinfo.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038
39namespace v8 {
40namespace internal {
41
42
43template <class C>
44static C* FindInPrototypeChain(Object* obj, bool* found_it) {
45 ASSERT(!*found_it);
Steve Block44f0eee2011-05-26 01:26:41 +010046 Heap* heap = HEAP;
Steve Blocka7e24c12009-10-30 11:49:00 +000047 while (!Is<C>(obj)) {
Steve Block44f0eee2011-05-26 01:26:41 +010048 if (obj == heap->null_value()) return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000049 obj = obj->GetPrototype();
50 }
51 *found_it = true;
52 return C::cast(obj);
53}
54
55
56// Entry point that never should be called.
John Reck59135872010-11-02 12:39:01 -070057MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000058 UNREACHABLE();
59 return NULL;
60}
61
62
63Object* Accessors::IllegalGetAccessor(Object* object, void*) {
64 UNREACHABLE();
65 return object;
66}
67
68
John Reck59135872010-11-02 12:39:01 -070069MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000070 // According to ECMA-262, section 8.6.2.2, page 28, setting
71 // read-only properties must be silently ignored.
72 return value;
73}
74
75
76//
77// Accessors::ArrayLength
78//
79
80
John Reck59135872010-11-02 12:39:01 -070081MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000082 // Traverse the prototype chain until we reach an array.
83 bool found_it = false;
84 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
85 if (!found_it) return Smi::FromInt(0);
86 return holder->length();
87}
88
89
90// The helper function will 'flatten' Number objects.
91Object* Accessors::FlattenNumber(Object* value) {
92 if (value->IsNumber() || !value->IsJSValue()) return value;
93 JSValue* wrapper = JSValue::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +010094 ASSERT(Isolate::Current()->context()->global_context()->number_function()->
95 has_initial_map());
96 Map* number_map = Isolate::Current()->context()->global_context()->
97 number_function()->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +000098 if (wrapper->map() == number_map) return wrapper->value();
99 return value;
100}
101
102
John Reck59135872010-11-02 12:39:01 -0700103MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100104 Isolate* isolate = object->GetIsolate();
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100105
106 // This means one of the object's prototypes is a JSArray and the
107 // object does not have a 'length' property. Calling SetProperty
108 // causes an infinite loop.
109 if (!object->IsJSArray()) {
110 return object->SetLocalPropertyIgnoreAttributes(
111 isolate->heap()->length_symbol(), value, NONE);
112 }
113
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 value = FlattenNumber(value);
115
116 // Need to call methods that may trigger GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100117 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000118
119 // Protect raw pointers.
Steve Block44f0eee2011-05-26 01:26:41 +0100120 Handle<JSObject> object_handle(object, isolate);
121 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000122
123 bool has_exception;
124 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
125 if (has_exception) return Failure::Exception();
126 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
127 if (has_exception) return Failure::Exception();
128
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 if (uint32_v->Number() == number_v->Number()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100130 return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 }
Steve Block44f0eee2011-05-26 01:26:41 +0100132 return isolate->Throw(
133 *isolate->factory()->NewRangeError("invalid_array_length",
134 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000135}
136
137
138const AccessorDescriptor Accessors::ArrayLength = {
139 ArrayGetLength,
140 ArraySetLength,
141 0
142};
143
144
145//
146// Accessors::StringLength
147//
148
149
John Reck59135872010-11-02 12:39:01 -0700150MaybeObject* Accessors::StringGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 Object* value = object;
152 if (object->IsJSValue()) value = JSValue::cast(object)->value();
153 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
154 // If object is not a string we return 0 to be compatible with WebKit.
155 // Note: Firefox returns the length of ToString(object).
156 return Smi::FromInt(0);
157}
158
159
160const AccessorDescriptor Accessors::StringLength = {
161 StringGetLength,
162 IllegalSetter,
163 0
164};
165
166
167//
168// Accessors::ScriptSource
169//
170
171
John Reck59135872010-11-02 12:39:01 -0700172MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 Object* script = JSValue::cast(object)->value();
174 return Script::cast(script)->source();
175}
176
177
178const AccessorDescriptor Accessors::ScriptSource = {
179 ScriptGetSource,
180 IllegalSetter,
181 0
182};
183
184
185//
186// Accessors::ScriptName
187//
188
189
John Reck59135872010-11-02 12:39:01 -0700190MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000191 Object* script = JSValue::cast(object)->value();
192 return Script::cast(script)->name();
193}
194
195
196const AccessorDescriptor Accessors::ScriptName = {
197 ScriptGetName,
198 IllegalSetter,
199 0
200};
201
202
203//
204// Accessors::ScriptId
205//
206
207
John Reck59135872010-11-02 12:39:01 -0700208MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000209 Object* script = JSValue::cast(object)->value();
210 return Script::cast(script)->id();
211}
212
213
214const AccessorDescriptor Accessors::ScriptId = {
215 ScriptGetId,
216 IllegalSetter,
217 0
218};
219
220
221//
222// Accessors::ScriptLineOffset
223//
224
225
John Reck59135872010-11-02 12:39:01 -0700226MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000227 Object* script = JSValue::cast(object)->value();
228 return Script::cast(script)->line_offset();
229}
230
231
232const AccessorDescriptor Accessors::ScriptLineOffset = {
233 ScriptGetLineOffset,
234 IllegalSetter,
235 0
236};
237
238
239//
240// Accessors::ScriptColumnOffset
241//
242
243
John Reck59135872010-11-02 12:39:01 -0700244MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 Object* script = JSValue::cast(object)->value();
246 return Script::cast(script)->column_offset();
247}
248
249
250const AccessorDescriptor Accessors::ScriptColumnOffset = {
251 ScriptGetColumnOffset,
252 IllegalSetter,
253 0
254};
255
256
257//
258// Accessors::ScriptData
259//
260
261
John Reck59135872010-11-02 12:39:01 -0700262MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 Object* script = JSValue::cast(object)->value();
264 return Script::cast(script)->data();
265}
266
267
268const AccessorDescriptor Accessors::ScriptData = {
269 ScriptGetData,
270 IllegalSetter,
271 0
272};
273
274
275//
276// Accessors::ScriptType
277//
278
279
John Reck59135872010-11-02 12:39:01 -0700280MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000281 Object* script = JSValue::cast(object)->value();
282 return Script::cast(script)->type();
283}
284
285
286const AccessorDescriptor Accessors::ScriptType = {
287 ScriptGetType,
288 IllegalSetter,
289 0
290};
291
292
293//
294// Accessors::ScriptCompilationType
295//
296
297
John Reck59135872010-11-02 12:39:01 -0700298MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000299 Object* script = JSValue::cast(object)->value();
300 return Script::cast(script)->compilation_type();
301}
302
303
304const AccessorDescriptor Accessors::ScriptCompilationType = {
305 ScriptGetCompilationType,
306 IllegalSetter,
307 0
308};
309
310
311//
312// Accessors::ScriptGetLineEnds
313//
314
315
John Reck59135872010-11-02 12:39:01 -0700316MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100317 JSValue* wrapper = JSValue::cast(object);
318 Isolate* isolate = wrapper->GetIsolate();
319 HandleScope scope(isolate);
320 Handle<Script> script(Script::cast(wrapper->value()), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 InitScriptLineEnds(script);
Steve Blockd0582a62009-12-15 09:54:21 +0000322 ASSERT(script->line_ends()->IsFixedArray());
323 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800324 // We do not want anyone to modify this array from JS.
Steve Block44f0eee2011-05-26 01:26:41 +0100325 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
326 line_ends->map() == isolate->heap()->fixed_cow_array_map());
327 Handle<JSArray> js_array =
328 isolate->factory()->NewJSArrayWithElements(line_ends);
Steve Blockd0582a62009-12-15 09:54:21 +0000329 return *js_array;
Steve Blocka7e24c12009-10-30 11:49:00 +0000330}
331
332
333const AccessorDescriptor Accessors::ScriptLineEnds = {
334 ScriptGetLineEnds,
335 IllegalSetter,
336 0
337};
338
339
340//
341// Accessors::ScriptGetContextData
342//
343
344
John Reck59135872010-11-02 12:39:01 -0700345MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 Object* script = JSValue::cast(object)->value();
347 return Script::cast(script)->context_data();
348}
349
350
351const AccessorDescriptor Accessors::ScriptContextData = {
352 ScriptGetContextData,
353 IllegalSetter,
354 0
355};
356
357
358//
Steve Blockd0582a62009-12-15 09:54:21 +0000359// Accessors::ScriptGetEvalFromScript
Steve Blocka7e24c12009-10-30 11:49:00 +0000360//
361
362
John Reck59135872010-11-02 12:39:01 -0700363MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000364 Object* script = JSValue::cast(object)->value();
Steve Blockd0582a62009-12-15 09:54:21 +0000365 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
366 Handle<SharedFunctionInfo> eval_from_shared(
367 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
368
369 if (eval_from_shared->script()->IsScript()) {
370 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
371 return *GetScriptWrapper(eval_from_script);
372 }
373 }
Steve Block44f0eee2011-05-26 01:26:41 +0100374 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000375}
376
377
Steve Blockd0582a62009-12-15 09:54:21 +0000378const AccessorDescriptor Accessors::ScriptEvalFromScript = {
379 ScriptGetEvalFromScript,
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 IllegalSetter,
381 0
382};
383
384
385//
Steve Blockd0582a62009-12-15 09:54:21 +0000386// Accessors::ScriptGetEvalFromScriptPosition
Steve Blocka7e24c12009-10-30 11:49:00 +0000387//
388
389
John Reck59135872010-11-02 12:39:01 -0700390MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000391 HandleScope scope;
392 Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
393
394 // If this is not a script compiled through eval there is no eval position.
395 int compilation_type = Smi::cast(script->compilation_type())->value();
396 if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100397 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 }
399
400 // Get the function from where eval was called and find the source position
401 // from the instruction offset.
Steve Blockd0582a62009-12-15 09:54:21 +0000402 Handle<Code> code(SharedFunctionInfo::cast(
403 script->eval_from_shared())->code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
405 script->eval_from_instructions_offset()->value()));
406}
407
408
Steve Blockd0582a62009-12-15 09:54:21 +0000409const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
410 ScriptGetEvalFromScriptPosition,
411 IllegalSetter,
412 0
413};
414
415
416//
417// Accessors::ScriptGetEvalFromFunctionName
418//
419
420
John Reck59135872010-11-02 12:39:01 -0700421MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
Steve Blockd0582a62009-12-15 09:54:21 +0000422 Object* script = JSValue::cast(object)->value();
423 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
424 Script::cast(script)->eval_from_shared()));
425
426
427 // Find the name of the function calling eval.
428 if (!shared->name()->IsUndefined()) {
429 return shared->name();
430 } else {
431 return shared->inferred_name();
432 }
433}
434
435
436const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
437 ScriptGetEvalFromFunctionName,
Steve Blocka7e24c12009-10-30 11:49:00 +0000438 IllegalSetter,
439 0
440};
441
442
443//
444// Accessors::FunctionPrototype
445//
446
447
John Reck59135872010-11-02 12:39:01 -0700448MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100449 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000450 bool found_it = false;
451 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100452 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100453 while (!function->should_have_prototype()) {
454 found_it = false;
455 function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
456 &found_it);
457 // There has to be one because we hit the getter.
458 ASSERT(found_it);
459 }
460
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 if (!function->has_prototype()) {
John Reck59135872010-11-02 12:39:01 -0700462 Object* prototype;
Steve Block44f0eee2011-05-26 01:26:41 +0100463 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
John Reck59135872010-11-02 12:39:01 -0700464 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
465 }
466 Object* result;
467 { MaybeObject* maybe_result = function->SetPrototype(prototype);
468 if (!maybe_result->ToObject(&result)) return maybe_result;
469 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 }
471 return function->prototype();
472}
473
474
John Reck59135872010-11-02 12:39:01 -0700475MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
476 Object* value,
477 void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100478 Heap* heap = object->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 bool found_it = false;
480 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100481 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100482 if (!function->should_have_prototype()) {
483 // Since we hit this accessor, object will have no prototype property.
Steve Block44f0eee2011-05-26 01:26:41 +0100484 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100485 value,
486 NONE);
487 }
488
Steve Blocka7e24c12009-10-30 11:49:00 +0000489 if (function->has_initial_map()) {
490 // If the function has allocated the initial map
491 // replace it with a copy containing the new prototype.
John Reck59135872010-11-02 12:39:01 -0700492 Object* new_map;
493 { MaybeObject* maybe_new_map =
494 function->initial_map()->CopyDropTransitions();
495 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
496 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000497 function->set_initial_map(Map::cast(new_map));
498 }
John Reck59135872010-11-02 12:39:01 -0700499 Object* prototype;
500 { MaybeObject* maybe_prototype = function->SetPrototype(value);
501 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
502 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000503 ASSERT(function->prototype() == value);
504 return function;
505}
506
507
508const AccessorDescriptor Accessors::FunctionPrototype = {
509 FunctionGetPrototype,
510 FunctionSetPrototype,
511 0
512};
513
514
515//
516// Accessors::FunctionLength
517//
518
519
John Reck59135872010-11-02 12:39:01 -0700520MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000521 bool found_it = false;
522 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
523 if (!found_it) return Smi::FromInt(0);
524 // Check if already compiled.
Iain Merrick75681382010-08-19 15:07:18 +0100525 if (!function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 // If the function isn't compiled yet, the length is not computed
527 // correctly yet. Compile it now and return the right length.
528 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100529 Handle<JSFunction> handle(function);
530 if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception();
531 return Smi::FromInt(handle->shared()->length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000532 } else {
533 return Smi::FromInt(function->shared()->length());
534 }
535}
536
537
538const AccessorDescriptor Accessors::FunctionLength = {
539 FunctionGetLength,
540 ReadOnlySetAccessor,
541 0
542};
543
544
545//
546// Accessors::FunctionName
547//
548
549
John Reck59135872010-11-02 12:39:01 -0700550MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000551 bool found_it = false;
552 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100553 if (!found_it) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 return holder->shared()->name();
555}
556
557
558const AccessorDescriptor Accessors::FunctionName = {
559 FunctionGetName,
560 ReadOnlySetAccessor,
561 0
562};
563
564
565//
566// Accessors::FunctionArguments
567//
568
Ben Murdochb0fe1622011-05-05 13:52:32 +0100569
570static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
571 JavaScriptFrame* frame,
572 Handle<JSFunction> inlined_function,
573 int inlined_frame_index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100574 Factory* factory = Isolate::Current()->factory();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100575 int args_count = inlined_function->shared()->formal_parameter_count();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100576 ScopedVector<SlotRef> args_slots(args_count);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100577 SlotRef::ComputeSlotMappingForArguments(frame,
578 inlined_frame_index,
579 &args_slots);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100580 Handle<JSObject> arguments =
Steve Block44f0eee2011-05-26 01:26:41 +0100581 factory->NewArgumentsObject(inlined_function, args_count);
582 Handle<FixedArray> array = factory->NewFixedArray(args_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100583 for (int i = 0; i < args_count; ++i) {
584 Handle<Object> value = args_slots[i].GetValue();
585 array->set(i, *value);
586 }
587 arguments->set_elements(*array);
588
589 // Return the freshly allocated arguments object.
590 return *arguments;
591}
592
Steve Blocka7e24c12009-10-30 11:49:00 +0000593
John Reck59135872010-11-02 12:39:01 -0700594MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100595 Isolate* isolate = Isolate::Current();
596 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000597 bool found_it = false;
598 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100599 if (!found_it) return isolate->heap()->undefined_value();
600 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000601
Ben Murdoch589d6972011-11-30 16:04:58 +0000602 if (function->shared()->native()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000603 // Find the top invocation of the function by traversing frames.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100604 List<JSFunction*> functions(2);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100605 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 JavaScriptFrame* frame = it.frame();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100607 frame->GetFunctions(&functions);
608 for (int i = functions.length() - 1; i >= 0; i--) {
609 // Skip all frames that aren't invocations of the given function.
610 if (functions[i] != *function) continue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000611
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612 if (i > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +0100613 // The function in question was inlined. Inlined functions have the
614 // correct number of arguments and no allocated arguments object, so
615 // we can construct a fresh one by interpreting the function's
616 // deoptimization input data.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100617 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
Steve Block1e0659c2011-05-24 12:43:12 +0100618 }
619
620 if (!frame->is_optimized()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100621 // If there is an arguments variable in the stack, we return that.
Steve Block1e0659c2011-05-24 12:43:12 +0100622 Handle<SerializedScopeInfo> info(function->shared()->scope_info());
Steve Block44f0eee2011-05-26 01:26:41 +0100623 int index = info->StackSlotIndex(isolate->heap()->arguments_symbol());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100624 if (index >= 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100625 Handle<Object> arguments(frame->GetExpression(index), isolate);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100626 if (!arguments->IsArgumentsMarker()) return *arguments;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100627 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100628 }
Steve Block1e0659c2011-05-24 12:43:12 +0100629
630 // If there is no arguments variable in the stack or we have an
631 // optimized frame, we find the frame that holds the actual arguments
632 // passed to the function.
633 it.AdvanceToArgumentsFrame();
634 frame = it.frame();
635
636 // Get the number of arguments and construct an arguments object
637 // mirror for the right frame.
Steve Block44f0eee2011-05-26 01:26:41 +0100638 const int length = frame->ComputeParametersCount();
639 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
640 function, length);
641 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
Steve Block1e0659c2011-05-24 12:43:12 +0100642
643 // Copy the parameters to the arguments object.
644 ASSERT(array->length() == length);
645 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
646 arguments->set_elements(*array);
647
648 // Return the freshly allocated arguments object.
649 return *arguments;
Steve Blocka7e24c12009-10-30 11:49:00 +0000650 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100651 functions.Rewind(0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 }
653
654 // No frame corresponding to the given function found. Return null.
Steve Block44f0eee2011-05-26 01:26:41 +0100655 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000656}
657
658
659const AccessorDescriptor Accessors::FunctionArguments = {
660 FunctionGetArguments,
661 ReadOnlySetAccessor,
662 0
663};
664
665
666//
667// Accessors::FunctionCaller
668//
669
670
Steve Block44f0eee2011-05-26 01:26:41 +0100671static MaybeObject* CheckNonStrictCallerOrThrow(
672 Isolate* isolate,
673 JSFunction* caller) {
674 DisableAssertNoAllocation enable_allocation;
675 if (caller->shared()->strict_mode()) {
676 return isolate->Throw(
677 *isolate->factory()->NewTypeError("strict_caller",
678 HandleVector<Object>(NULL, 0)));
679 }
680 return caller;
681}
682
683
Ben Murdoch257744e2011-11-30 15:57:28 +0000684class FrameFunctionIterator {
685 public:
686 FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
687 : frame_iterator_(isolate),
688 functions_(2),
689 index_(0) {
690 GetFunctions();
691 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000692 JSFunction* next() {
693 if (functions_.length() == 0) return NULL;
694 JSFunction* next_function = functions_[index_];
695 index_--;
696 if (index_ < 0) {
697 GetFunctions();
698 }
699 return next_function;
700 }
701
702 // Iterate through functions until the first occurence of 'function'.
703 // Returns true if 'function' is found, and false if the iterator ends
704 // without finding it.
705 bool Find(JSFunction* function) {
706 JSFunction* next_function;
707 do {
708 next_function = next();
709 if (next_function == function) return true;
710 } while (next_function != NULL);
711 return false;
712 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000713
Ben Murdoch257744e2011-11-30 15:57:28 +0000714 private:
715 void GetFunctions() {
716 functions_.Rewind(0);
717 if (frame_iterator_.done()) return;
718 JavaScriptFrame* frame = frame_iterator_.frame();
719 frame->GetFunctions(&functions_);
720 ASSERT(functions_.length() > 0);
721 frame_iterator_.Advance();
722 index_ = functions_.length() - 1;
723 }
724 JavaScriptFrameIterator frame_iterator_;
725 List<JSFunction*> functions_;
726 int index_;
727};
728
729
John Reck59135872010-11-02 12:39:01 -0700730MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100731 Isolate* isolate = Isolate::Current();
732 HandleScope scope(isolate);
John Reck59135872010-11-02 12:39:01 -0700733 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 bool found_it = false;
735 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100736 if (!found_it) return isolate->heap()->undefined_value();
Ben Murdoch589d6972011-11-30 16:04:58 +0000737 if (holder->shared()->native()) return isolate->heap()->null_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100738 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000739
Ben Murdoch257744e2011-11-30 15:57:28 +0000740 FrameFunctionIterator it(isolate, no_alloc);
741
742 // Find the function from the frames.
743 if (!it.Find(*function)) {
744 // No frame corresponding to the given function found. Return null.
745 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000746 }
747
Ben Murdoch257744e2011-11-30 15:57:28 +0000748 // Find previously called non-toplevel function.
749 JSFunction* caller;
750 do {
751 caller = it.next();
752 if (caller == NULL) return isolate->heap()->null_value();
753 } while (caller->shared()->is_toplevel());
754
755 // If caller is a built-in function and caller's caller is also built-in,
756 // use that instead.
757 JSFunction* potential_caller = caller;
758 while (potential_caller != NULL && potential_caller->IsBuiltin()) {
759 caller = potential_caller;
760 potential_caller = it.next();
761 }
762
763 return CheckNonStrictCallerOrThrow(isolate, caller);
Steve Blocka7e24c12009-10-30 11:49:00 +0000764}
765
766
767const AccessorDescriptor Accessors::FunctionCaller = {
768 FunctionGetCaller,
769 ReadOnlySetAccessor,
770 0
771};
772
773
774//
775// Accessors::ObjectPrototype
776//
777
778
John Reck59135872010-11-02 12:39:01 -0700779MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000780 Object* current = receiver->GetPrototype();
781 while (current->IsJSObject() &&
782 JSObject::cast(current)->map()->is_hidden_prototype()) {
783 current = current->GetPrototype();
784 }
785 return current;
786}
787
788
John Reck59135872010-11-02 12:39:01 -0700789MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
790 Object* value,
791 void*) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000792 const bool skip_hidden_prototypes = true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000793 // To be consistent with other Set functions, return the value.
Andrei Popescu402d9372010-02-26 13:31:12 +0000794 return receiver->SetPrototype(value, skip_hidden_prototypes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000795}
796
797
798const AccessorDescriptor Accessors::ObjectPrototype = {
799 ObjectGetPrototype,
800 ObjectSetPrototype,
801 0
802};
803
804} } // namespace v8::internal