blob: 9b16525b4c10e7607117d9be3d4c4bce1b5df11d [file] [log] [blame]
Ben Murdochc7cc0282012-03-05 14:35:55 +00001// Copyright 2012 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"
Steve Blocka7e24c12009-10-30 11:49:00 +000029#include "accessors.h"
Ben Murdochc7cc0282012-03-05 14:35:55 +000030
31#include "contexts.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010032#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "execution.h"
34#include "factory.h"
Ben Murdochc7cc0282012-03-05 14:35:55 +000035#include "frames-inl.h"
36#include "isolate.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000037#include "list-inl.h"
Ben Murdochc7cc0282012-03-05 14:35:55 +000038#include "property-details.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039
40namespace v8 {
41namespace internal {
42
43
44template <class C>
45static C* FindInPrototypeChain(Object* obj, bool* found_it) {
46 ASSERT(!*found_it);
Steve Block44f0eee2011-05-26 01:26:41 +010047 Heap* heap = HEAP;
Steve Blocka7e24c12009-10-30 11:49:00 +000048 while (!Is<C>(obj)) {
Steve Block44f0eee2011-05-26 01:26:41 +010049 if (obj == heap->null_value()) return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000050 obj = obj->GetPrototype();
51 }
52 *found_it = true;
53 return C::cast(obj);
54}
55
56
57// Entry point that never should be called.
John Reck59135872010-11-02 12:39:01 -070058MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000059 UNREACHABLE();
60 return NULL;
61}
62
63
64Object* Accessors::IllegalGetAccessor(Object* object, void*) {
65 UNREACHABLE();
66 return object;
67}
68
69
John Reck59135872010-11-02 12:39:01 -070070MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000071 // According to ECMA-262, section 8.6.2.2, page 28, setting
72 // read-only properties must be silently ignored.
73 return value;
74}
75
76
77//
78// Accessors::ArrayLength
79//
80
81
John Reck59135872010-11-02 12:39:01 -070082MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000083 // Traverse the prototype chain until we reach an array.
84 bool found_it = false;
85 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
86 if (!found_it) return Smi::FromInt(0);
87 return holder->length();
88}
89
90
91// The helper function will 'flatten' Number objects.
92Object* Accessors::FlattenNumber(Object* value) {
93 if (value->IsNumber() || !value->IsJSValue()) return value;
94 JSValue* wrapper = JSValue::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +010095 ASSERT(Isolate::Current()->context()->global_context()->number_function()->
96 has_initial_map());
97 Map* number_map = Isolate::Current()->context()->global_context()->
98 number_function()->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +000099 if (wrapper->map() == number_map) return wrapper->value();
100 return value;
101}
102
103
John Reck59135872010-11-02 12:39:01 -0700104MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100105 Isolate* isolate = object->GetIsolate();
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100106
107 // This means one of the object's prototypes is a JSArray and the
108 // object does not have a 'length' property. Calling SetProperty
109 // causes an infinite loop.
110 if (!object->IsJSArray()) {
111 return object->SetLocalPropertyIgnoreAttributes(
112 isolate->heap()->length_symbol(), value, NONE);
113 }
114
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 value = FlattenNumber(value);
116
117 // Need to call methods that may trigger GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100118 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000119
120 // Protect raw pointers.
Steve Block44f0eee2011-05-26 01:26:41 +0100121 Handle<JSObject> object_handle(object, isolate);
122 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
124 bool has_exception;
125 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
126 if (has_exception) return Failure::Exception();
127 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
128 if (has_exception) return Failure::Exception();
129
Steve Blocka7e24c12009-10-30 11:49:00 +0000130 if (uint32_v->Number() == number_v->Number()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100131 return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
Steve Blocka7e24c12009-10-30 11:49:00 +0000132 }
Steve Block44f0eee2011-05-26 01:26:41 +0100133 return isolate->Throw(
134 *isolate->factory()->NewRangeError("invalid_array_length",
135 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000136}
137
138
139const AccessorDescriptor Accessors::ArrayLength = {
140 ArrayGetLength,
141 ArraySetLength,
142 0
143};
144
145
146//
147// Accessors::StringLength
148//
149
150
John Reck59135872010-11-02 12:39:01 -0700151MaybeObject* Accessors::StringGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000152 Object* value = object;
153 if (object->IsJSValue()) value = JSValue::cast(object)->value();
154 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
155 // If object is not a string we return 0 to be compatible with WebKit.
156 // Note: Firefox returns the length of ToString(object).
157 return Smi::FromInt(0);
158}
159
160
161const AccessorDescriptor Accessors::StringLength = {
162 StringGetLength,
163 IllegalSetter,
164 0
165};
166
167
168//
169// Accessors::ScriptSource
170//
171
172
John Reck59135872010-11-02 12:39:01 -0700173MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 Object* script = JSValue::cast(object)->value();
175 return Script::cast(script)->source();
176}
177
178
179const AccessorDescriptor Accessors::ScriptSource = {
180 ScriptGetSource,
181 IllegalSetter,
182 0
183};
184
185
186//
187// Accessors::ScriptName
188//
189
190
John Reck59135872010-11-02 12:39:01 -0700191MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 Object* script = JSValue::cast(object)->value();
193 return Script::cast(script)->name();
194}
195
196
197const AccessorDescriptor Accessors::ScriptName = {
198 ScriptGetName,
199 IllegalSetter,
200 0
201};
202
203
204//
205// Accessors::ScriptId
206//
207
208
John Reck59135872010-11-02 12:39:01 -0700209MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 Object* script = JSValue::cast(object)->value();
211 return Script::cast(script)->id();
212}
213
214
215const AccessorDescriptor Accessors::ScriptId = {
216 ScriptGetId,
217 IllegalSetter,
218 0
219};
220
221
222//
223// Accessors::ScriptLineOffset
224//
225
226
John Reck59135872010-11-02 12:39:01 -0700227MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 Object* script = JSValue::cast(object)->value();
229 return Script::cast(script)->line_offset();
230}
231
232
233const AccessorDescriptor Accessors::ScriptLineOffset = {
234 ScriptGetLineOffset,
235 IllegalSetter,
236 0
237};
238
239
240//
241// Accessors::ScriptColumnOffset
242//
243
244
John Reck59135872010-11-02 12:39:01 -0700245MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000246 Object* script = JSValue::cast(object)->value();
247 return Script::cast(script)->column_offset();
248}
249
250
251const AccessorDescriptor Accessors::ScriptColumnOffset = {
252 ScriptGetColumnOffset,
253 IllegalSetter,
254 0
255};
256
257
258//
259// Accessors::ScriptData
260//
261
262
John Reck59135872010-11-02 12:39:01 -0700263MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000264 Object* script = JSValue::cast(object)->value();
265 return Script::cast(script)->data();
266}
267
268
269const AccessorDescriptor Accessors::ScriptData = {
270 ScriptGetData,
271 IllegalSetter,
272 0
273};
274
275
276//
277// Accessors::ScriptType
278//
279
280
John Reck59135872010-11-02 12:39:01 -0700281MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000282 Object* script = JSValue::cast(object)->value();
283 return Script::cast(script)->type();
284}
285
286
287const AccessorDescriptor Accessors::ScriptType = {
288 ScriptGetType,
289 IllegalSetter,
290 0
291};
292
293
294//
295// Accessors::ScriptCompilationType
296//
297
298
John Reck59135872010-11-02 12:39:01 -0700299MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 Object* script = JSValue::cast(object)->value();
301 return Script::cast(script)->compilation_type();
302}
303
304
305const AccessorDescriptor Accessors::ScriptCompilationType = {
306 ScriptGetCompilationType,
307 IllegalSetter,
308 0
309};
310
311
312//
313// Accessors::ScriptGetLineEnds
314//
315
316
John Reck59135872010-11-02 12:39:01 -0700317MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100318 JSValue* wrapper = JSValue::cast(object);
319 Isolate* isolate = wrapper->GetIsolate();
320 HandleScope scope(isolate);
321 Handle<Script> script(Script::cast(wrapper->value()), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000322 InitScriptLineEnds(script);
Steve Blockd0582a62009-12-15 09:54:21 +0000323 ASSERT(script->line_ends()->IsFixedArray());
324 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800325 // We do not want anyone to modify this array from JS.
Steve Block44f0eee2011-05-26 01:26:41 +0100326 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
327 line_ends->map() == isolate->heap()->fixed_cow_array_map());
328 Handle<JSArray> js_array =
329 isolate->factory()->NewJSArrayWithElements(line_ends);
Steve Blockd0582a62009-12-15 09:54:21 +0000330 return *js_array;
Steve Blocka7e24c12009-10-30 11:49:00 +0000331}
332
333
334const AccessorDescriptor Accessors::ScriptLineEnds = {
335 ScriptGetLineEnds,
336 IllegalSetter,
337 0
338};
339
340
341//
342// Accessors::ScriptGetContextData
343//
344
345
John Reck59135872010-11-02 12:39:01 -0700346MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 Object* script = JSValue::cast(object)->value();
348 return Script::cast(script)->context_data();
349}
350
351
352const AccessorDescriptor Accessors::ScriptContextData = {
353 ScriptGetContextData,
354 IllegalSetter,
355 0
356};
357
358
359//
Steve Blockd0582a62009-12-15 09:54:21 +0000360// Accessors::ScriptGetEvalFromScript
Steve Blocka7e24c12009-10-30 11:49:00 +0000361//
362
363
John Reck59135872010-11-02 12:39:01 -0700364MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 Object* script = JSValue::cast(object)->value();
Steve Blockd0582a62009-12-15 09:54:21 +0000366 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
367 Handle<SharedFunctionInfo> eval_from_shared(
368 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
369
370 if (eval_from_shared->script()->IsScript()) {
371 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
372 return *GetScriptWrapper(eval_from_script);
373 }
374 }
Steve Block44f0eee2011-05-26 01:26:41 +0100375 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000376}
377
378
Steve Blockd0582a62009-12-15 09:54:21 +0000379const AccessorDescriptor Accessors::ScriptEvalFromScript = {
380 ScriptGetEvalFromScript,
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 IllegalSetter,
382 0
383};
384
385
386//
Steve Blockd0582a62009-12-15 09:54:21 +0000387// Accessors::ScriptGetEvalFromScriptPosition
Steve Blocka7e24c12009-10-30 11:49:00 +0000388//
389
390
John Reck59135872010-11-02 12:39:01 -0700391MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 HandleScope scope;
393 Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
394
395 // If this is not a script compiled through eval there is no eval position.
396 int compilation_type = Smi::cast(script->compilation_type())->value();
397 if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100398 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 }
400
401 // Get the function from where eval was called and find the source position
402 // from the instruction offset.
Steve Blockd0582a62009-12-15 09:54:21 +0000403 Handle<Code> code(SharedFunctionInfo::cast(
404 script->eval_from_shared())->code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000405 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
406 script->eval_from_instructions_offset()->value()));
407}
408
409
Steve Blockd0582a62009-12-15 09:54:21 +0000410const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
411 ScriptGetEvalFromScriptPosition,
412 IllegalSetter,
413 0
414};
415
416
417//
418// Accessors::ScriptGetEvalFromFunctionName
419//
420
421
John Reck59135872010-11-02 12:39:01 -0700422MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
Steve Blockd0582a62009-12-15 09:54:21 +0000423 Object* script = JSValue::cast(object)->value();
424 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
425 Script::cast(script)->eval_from_shared()));
426
427
428 // Find the name of the function calling eval.
429 if (!shared->name()->IsUndefined()) {
430 return shared->name();
431 } else {
432 return shared->inferred_name();
433 }
434}
435
436
437const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
438 ScriptGetEvalFromFunctionName,
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 IllegalSetter,
440 0
441};
442
443
444//
445// Accessors::FunctionPrototype
446//
447
448
John Reck59135872010-11-02 12:39:01 -0700449MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100450 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000451 bool found_it = false;
452 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100453 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100454 while (!function->should_have_prototype()) {
455 found_it = false;
456 function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
457 &found_it);
458 // There has to be one because we hit the getter.
459 ASSERT(found_it);
460 }
461
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 if (!function->has_prototype()) {
John Reck59135872010-11-02 12:39:01 -0700463 Object* prototype;
Steve Block44f0eee2011-05-26 01:26:41 +0100464 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
John Reck59135872010-11-02 12:39:01 -0700465 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
466 }
467 Object* result;
468 { MaybeObject* maybe_result = function->SetPrototype(prototype);
469 if (!maybe_result->ToObject(&result)) return maybe_result;
470 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000471 }
472 return function->prototype();
473}
474
475
John Reck59135872010-11-02 12:39:01 -0700476MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
477 Object* value,
478 void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100479 Heap* heap = object->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 bool found_it = false;
481 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100482 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100483 if (!function->should_have_prototype()) {
484 // Since we hit this accessor, object will have no prototype property.
Steve Block44f0eee2011-05-26 01:26:41 +0100485 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100486 value,
487 NONE);
488 }
489
Steve Blocka7e24c12009-10-30 11:49:00 +0000490 if (function->has_initial_map()) {
491 // If the function has allocated the initial map
492 // replace it with a copy containing the new prototype.
John Reck59135872010-11-02 12:39:01 -0700493 Object* new_map;
494 { MaybeObject* maybe_new_map =
495 function->initial_map()->CopyDropTransitions();
496 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
497 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000498 function->set_initial_map(Map::cast(new_map));
499 }
John Reck59135872010-11-02 12:39:01 -0700500 Object* prototype;
501 { MaybeObject* maybe_prototype = function->SetPrototype(value);
502 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
503 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000504 ASSERT(function->prototype() == value);
505 return function;
506}
507
508
509const AccessorDescriptor Accessors::FunctionPrototype = {
510 FunctionGetPrototype,
511 FunctionSetPrototype,
512 0
513};
514
515
516//
517// Accessors::FunctionLength
518//
519
520
John Reck59135872010-11-02 12:39:01 -0700521MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000522 bool found_it = false;
523 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
524 if (!found_it) return Smi::FromInt(0);
525 // Check if already compiled.
Iain Merrick75681382010-08-19 15:07:18 +0100526 if (!function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 // If the function isn't compiled yet, the length is not computed
528 // correctly yet. Compile it now and return the right length.
529 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100530 Handle<JSFunction> handle(function);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000531 if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
532 return Failure::Exception();
533 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100534 return Smi::FromInt(handle->shared()->length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000535 } else {
536 return Smi::FromInt(function->shared()->length());
537 }
538}
539
540
541const AccessorDescriptor Accessors::FunctionLength = {
542 FunctionGetLength,
543 ReadOnlySetAccessor,
544 0
545};
546
547
548//
549// Accessors::FunctionName
550//
551
552
John Reck59135872010-11-02 12:39:01 -0700553MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 bool found_it = false;
555 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100556 if (!found_it) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000557 return holder->shared()->name();
558}
559
560
561const AccessorDescriptor Accessors::FunctionName = {
562 FunctionGetName,
563 ReadOnlySetAccessor,
564 0
565};
566
567
568//
569// Accessors::FunctionArguments
570//
571
Ben Murdochb0fe1622011-05-05 13:52:32 +0100572
573static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
574 JavaScriptFrame* frame,
575 Handle<JSFunction> inlined_function,
576 int inlined_frame_index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100577 Factory* factory = Isolate::Current()->factory();
Ben Murdochc7cc0282012-03-05 14:35:55 +0000578 Vector<SlotRef> args_slots =
579 SlotRef::ComputeSlotMappingForArguments(
580 frame,
581 inlined_frame_index,
582 inlined_function->shared()->formal_parameter_count());
583 int args_count = args_slots.length();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100584 Handle<JSObject> arguments =
Steve Block44f0eee2011-05-26 01:26:41 +0100585 factory->NewArgumentsObject(inlined_function, args_count);
586 Handle<FixedArray> array = factory->NewFixedArray(args_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100587 for (int i = 0; i < args_count; ++i) {
588 Handle<Object> value = args_slots[i].GetValue();
589 array->set(i, *value);
590 }
591 arguments->set_elements(*array);
Ben Murdochc7cc0282012-03-05 14:35:55 +0000592 args_slots.Dispose();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100593
594 // Return the freshly allocated arguments object.
595 return *arguments;
596}
597
Steve Blocka7e24c12009-10-30 11:49:00 +0000598
John Reck59135872010-11-02 12:39:01 -0700599MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100600 Isolate* isolate = Isolate::Current();
601 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 bool found_it = false;
603 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100604 if (!found_it) return isolate->heap()->undefined_value();
605 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000606
Ben Murdoch589d6972011-11-30 16:04:58 +0000607 if (function->shared()->native()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 // Find the top invocation of the function by traversing frames.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100609 List<JSFunction*> functions(2);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100610 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000611 JavaScriptFrame* frame = it.frame();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612 frame->GetFunctions(&functions);
613 for (int i = functions.length() - 1; i >= 0; i--) {
614 // Skip all frames that aren't invocations of the given function.
615 if (functions[i] != *function) continue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000616
Ben Murdochb0fe1622011-05-05 13:52:32 +0100617 if (i > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +0100618 // The function in question was inlined. Inlined functions have the
619 // correct number of arguments and no allocated arguments object, so
620 // we can construct a fresh one by interpreting the function's
621 // deoptimization input data.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100622 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
Steve Block1e0659c2011-05-24 12:43:12 +0100623 }
624
625 if (!frame->is_optimized()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100626 // If there is an arguments variable in the stack, we return that.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000627 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
628 int index = scope_info->StackSlotIndex(
629 isolate->heap()->arguments_symbol());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100630 if (index >= 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100631 Handle<Object> arguments(frame->GetExpression(index), isolate);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100632 if (!arguments->IsArgumentsMarker()) return *arguments;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100633 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100634 }
Steve Block1e0659c2011-05-24 12:43:12 +0100635
636 // If there is no arguments variable in the stack or we have an
637 // optimized frame, we find the frame that holds the actual arguments
638 // passed to the function.
639 it.AdvanceToArgumentsFrame();
640 frame = it.frame();
641
642 // Get the number of arguments and construct an arguments object
643 // mirror for the right frame.
Steve Block44f0eee2011-05-26 01:26:41 +0100644 const int length = frame->ComputeParametersCount();
645 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
646 function, length);
647 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
Steve Block1e0659c2011-05-24 12:43:12 +0100648
649 // Copy the parameters to the arguments object.
650 ASSERT(array->length() == length);
651 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
652 arguments->set_elements(*array);
653
654 // Return the freshly allocated arguments object.
655 return *arguments;
Steve Blocka7e24c12009-10-30 11:49:00 +0000656 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100657 functions.Rewind(0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000658 }
659
660 // No frame corresponding to the given function found. Return null.
Steve Block44f0eee2011-05-26 01:26:41 +0100661 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000662}
663
664
665const AccessorDescriptor Accessors::FunctionArguments = {
666 FunctionGetArguments,
667 ReadOnlySetAccessor,
668 0
669};
670
671
672//
673// Accessors::FunctionCaller
674//
675
676
Steve Block44f0eee2011-05-26 01:26:41 +0100677static MaybeObject* CheckNonStrictCallerOrThrow(
678 Isolate* isolate,
679 JSFunction* caller) {
680 DisableAssertNoAllocation enable_allocation;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000681 if (!caller->shared()->is_classic_mode()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100682 return isolate->Throw(
683 *isolate->factory()->NewTypeError("strict_caller",
684 HandleVector<Object>(NULL, 0)));
685 }
686 return caller;
687}
688
689
Ben Murdoch257744e2011-11-30 15:57:28 +0000690class FrameFunctionIterator {
691 public:
692 FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
693 : frame_iterator_(isolate),
694 functions_(2),
695 index_(0) {
696 GetFunctions();
697 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000698 JSFunction* next() {
699 if (functions_.length() == 0) return NULL;
700 JSFunction* next_function = functions_[index_];
701 index_--;
702 if (index_ < 0) {
703 GetFunctions();
704 }
705 return next_function;
706 }
707
708 // Iterate through functions until the first occurence of 'function'.
709 // Returns true if 'function' is found, and false if the iterator ends
710 // without finding it.
711 bool Find(JSFunction* function) {
712 JSFunction* next_function;
713 do {
714 next_function = next();
715 if (next_function == function) return true;
716 } while (next_function != NULL);
717 return false;
718 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000719
Ben Murdoch257744e2011-11-30 15:57:28 +0000720 private:
721 void GetFunctions() {
722 functions_.Rewind(0);
723 if (frame_iterator_.done()) return;
724 JavaScriptFrame* frame = frame_iterator_.frame();
725 frame->GetFunctions(&functions_);
726 ASSERT(functions_.length() > 0);
727 frame_iterator_.Advance();
728 index_ = functions_.length() - 1;
729 }
730 JavaScriptFrameIterator frame_iterator_;
731 List<JSFunction*> functions_;
732 int index_;
733};
734
735
John Reck59135872010-11-02 12:39:01 -0700736MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100737 Isolate* isolate = Isolate::Current();
738 HandleScope scope(isolate);
John Reck59135872010-11-02 12:39:01 -0700739 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000740 bool found_it = false;
741 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100742 if (!found_it) return isolate->heap()->undefined_value();
Ben Murdoch589d6972011-11-30 16:04:58 +0000743 if (holder->shared()->native()) return isolate->heap()->null_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100744 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000745
Ben Murdoch257744e2011-11-30 15:57:28 +0000746 FrameFunctionIterator it(isolate, no_alloc);
747
748 // Find the function from the frames.
749 if (!it.Find(*function)) {
750 // No frame corresponding to the given function found. Return null.
751 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 }
753
Ben Murdoch257744e2011-11-30 15:57:28 +0000754 // Find previously called non-toplevel function.
755 JSFunction* caller;
756 do {
757 caller = it.next();
758 if (caller == NULL) return isolate->heap()->null_value();
759 } while (caller->shared()->is_toplevel());
760
761 // If caller is a built-in function and caller's caller is also built-in,
762 // use that instead.
763 JSFunction* potential_caller = caller;
764 while (potential_caller != NULL && potential_caller->IsBuiltin()) {
765 caller = potential_caller;
766 potential_caller = it.next();
767 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000768 // If caller is bound, return null. This is compatible with JSC, and
769 // allows us to make bound functions use the strict function map
770 // and its associated throwing caller and arguments.
771 if (caller->shared()->bound()) {
772 return isolate->heap()->null_value();
773 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000774 return CheckNonStrictCallerOrThrow(isolate, caller);
Steve Blocka7e24c12009-10-30 11:49:00 +0000775}
776
777
778const AccessorDescriptor Accessors::FunctionCaller = {
779 FunctionGetCaller,
780 ReadOnlySetAccessor,
781 0
782};
783
784
785//
786// Accessors::ObjectPrototype
787//
788
789
John Reck59135872010-11-02 12:39:01 -0700790MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000791 Object* current = receiver->GetPrototype();
792 while (current->IsJSObject() &&
793 JSObject::cast(current)->map()->is_hidden_prototype()) {
794 current = current->GetPrototype();
795 }
796 return current;
797}
798
799
John Reck59135872010-11-02 12:39:01 -0700800MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
801 Object* value,
802 void*) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000803 const bool skip_hidden_prototypes = true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000804 // To be consistent with other Set functions, return the value.
Andrei Popescu402d9372010-02-26 13:31:12 +0000805 return receiver->SetPrototype(value, skip_hidden_prototypes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000806}
807
808
809const AccessorDescriptor Accessors::ObjectPrototype = {
810 ObjectGetPrototype,
811 ObjectSetPrototype,
812 0
813};
814
815} } // namespace v8::internal