blob: 019851e466a363948a3338c171eeac531b0290c4 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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 <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000074 Type* name = Type::cast(args[index]);
75
76#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000083#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
84 RUNTIME_ASSERT(args[index]->IsBoolean()); \
85 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000109// Cast the given argument to PropertyDetails and store its value in a
110// variable with the given name. If the argument is not a Smi call
111// IllegalOperation and return.
112#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
113 RUNTIME_ASSERT(args[index]->IsSmi()); \
114 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
115
116
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000117// Assert that the given argument has a valid value for a StrictModeFlag
118// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000119#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
120 RUNTIME_ASSERT(args[index]->IsSmi()); \
121 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
122 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000123 StrictModeFlag name = \
124 static_cast<StrictModeFlag>(args.smi_at(index));
125
126
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000127// Assert that the given argument has a valid value for a LanguageMode
128// and store it in a LanguageMode variable with the given name.
129#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
130 ASSERT(args[index]->IsSmi()); \
131 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
132 args.smi_at(index) == STRICT_MODE || \
133 args.smi_at(index) == EXTENDED_MODE); \
134 LanguageMode name = \
135 static_cast<LanguageMode>(args.smi_at(index));
136
137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
139 JSObject* boilerplate) {
140 StackLimitCheck check(isolate);
141 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 JSObject* copy = JSObject::cast(result);
149
150 // Deep copy local properties.
151 if (copy->HasFastProperties()) {
152 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 for (int i = 0; i < properties->length(); i++) {
154 Object* value = properties->get(i);
155 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 }
162 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000163 int nof = copy->map()->inobject_properties();
164 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 Object* value = copy->InObjectPropertyAt(i);
166 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000171 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000175 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000176 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000177 if (!maybe_result->ToObject(&result)) return maybe_result;
178 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000179 FixedArray* names = FixedArray::cast(result);
180 copy->GetLocalPropertyNames(names, 0);
181 for (int i = 0; i < names->length(); i++) {
182 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000183 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000186 // Only deep copy fields from the object literal expression.
187 // In particular, don't try to copy the length attribute of
188 // an array.
189 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000190 Object* value =
191 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000192 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
197 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000198 // Creating object copy for literals. No strict mode needed.
199 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000200 if (!maybe_result->ToObject(&result)) return maybe_result;
201 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
203 }
204 }
205
206 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000208 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000210 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000211 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 if (elements->map() == heap->fixed_cow_array_map()) {
214 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000215#ifdef DEBUG
216 for (int i = 0; i < elements->length(); i++) {
217 ASSERT(!elements->get(i)->IsJSObject());
218 }
219#endif
220 } else {
221 for (int i = 0; i < elements->length(); i++) {
222 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000223 ASSERT(value->IsSmi() ||
224 value->IsTheHole() ||
225 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000226 if (value->IsJSObject()) {
227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000232 elements->set(i, result);
233 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000234 }
235 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000239 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000240 int capacity = element_dictionary->Capacity();
241 for (int i = 0; i < capacity; i++) {
242 Object* k = element_dictionary->KeyAt(i);
243 if (element_dictionary->IsKey(k)) {
244 Object* value = element_dictionary->ValueAt(i);
245 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
248 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000249 if (!maybe_result->ToObject(&result)) return maybe_result;
250 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000251 element_dictionary->ValueAtPut(i, result);
252 }
253 }
254 }
255 break;
256 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000257 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000258 UNIMPLEMENTED();
259 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000260 case EXTERNAL_PIXEL_ELEMENTS:
261 case EXTERNAL_BYTE_ELEMENTS:
262 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
263 case EXTERNAL_SHORT_ELEMENTS:
264 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
265 case EXTERNAL_INT_ELEMENTS:
266 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
267 case EXTERNAL_FLOAT_ELEMENTS:
268 case EXTERNAL_DOUBLE_ELEMENTS:
269 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000270 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000271 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000272 }
273 return copy;
274}
275
276
ager@chromium.org236ad962008-09-25 09:45:57 +0000277static Handle<Map> ComputeObjectLiteralMap(
278 Handle<Context> context,
279 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000282 int properties_length = constant_properties->length();
283 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000284 // Check that there are only symbols and array indices among keys.
285 int number_of_symbol_keys = 0;
286 for (int p = 0; p != properties_length; p += 2) {
287 Object* key = constant_properties->get(p);
288 uint32_t element_index = 0;
289 if (key->IsSymbol()) {
290 number_of_symbol_keys++;
291 } else if (key->ToArrayIndex(&element_index)) {
292 // An index key does not require space in the property backing store.
293 number_of_properties--;
294 } else {
295 // Bail out as a non-symbol non-index key makes caching impossible.
296 // ASSERT to make sure that the if condition after the loop is false.
297 ASSERT(number_of_symbol_keys != number_of_properties);
298 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000300 }
301 // If we only have symbols and array indices among keys then we can
302 // use the map cache in the global context.
303 const int kMaxKeys = 10;
304 if ((number_of_symbol_keys == number_of_properties) &&
305 (number_of_symbol_keys < kMaxKeys)) {
306 // Create the fixed array with the key.
307 Handle<FixedArray> keys =
308 isolate->factory()->NewFixedArray(number_of_symbol_keys);
309 if (number_of_symbol_keys > 0) {
310 int index = 0;
311 for (int p = 0; p < properties_length; p += 2) {
312 Object* key = constant_properties->get(p);
313 if (key->IsSymbol()) {
314 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000315 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000316 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000317 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000319 *is_result_from_cache = true;
320 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000322 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000324 Handle<Map>(context->object_function()->initial_map()),
325 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000326}
327
328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
332 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000333
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000334
335static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000336 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000337 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000338 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 bool should_have_fast_elements,
340 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000341 // Get the global context from the literals array. This is the
342 // context in which the function was created and we use the object
343 // function from this context to create the object literal. We do
344 // not use the object function from the current global context
345 // because this might be the object function from another context
346 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000347 Handle<Context> context =
348 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 // In case we have function literals, we want the object to be in
351 // slow properties mode for now. We don't go in the map cache because
352 // maps with constant functions can't be shared if the functions are
353 // not the same (which is the common case).
354 bool is_result_from_cache = false;
355 Handle<Map> map = has_function_literal
356 ? Handle<Map>(context->object_function()->initial_map())
357 : ComputeObjectLiteralMap(context,
358 constant_properties,
359 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000362
363 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000364 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 // Add the constant properties to the boilerplate.
367 int length = constant_properties->length();
368 bool should_transform =
369 !is_result_from_cache && boilerplate->HasFastProperties();
370 if (should_transform || has_function_literal) {
371 // Normalize the properties of object to avoid n^2 behavior
372 // when extending the object multiple properties. Indicate the number of
373 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000374 JSObject::NormalizeProperties(
375 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 }
377
378 for (int index = 0; index < length; index +=2) {
379 Handle<Object> key(constant_properties->get(index+0), isolate);
380 Handle<Object> value(constant_properties->get(index+1), isolate);
381 if (value->IsFixedArray()) {
382 // The value contains the constant_properties of a
383 // simple object or array literal.
384 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
385 value = CreateLiteralBoilerplate(isolate, literals, array);
386 if (value.is_null()) return value;
387 }
388 Handle<Object> result;
389 uint32_t element_index = 0;
390 if (key->IsSymbol()) {
391 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
392 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000393 result = JSObject::SetOwnElement(
394 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Handle<String> name(String::cast(*key));
397 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000398 result = JSObject::SetLocalPropertyIgnoreAttributes(
399 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 } else if (key->ToArrayIndex(&element_index)) {
402 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000403 result = JSObject::SetOwnElement(
404 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 } else {
406 // Non-uint32 number.
407 ASSERT(key->IsNumber());
408 double num = key->Number();
409 char arr[100];
410 Vector<char> buffer(arr, ARRAY_SIZE(arr));
411 const char* str = DoubleToCString(num, buffer);
412 Handle<String> name =
413 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000414 result = JSObject::SetLocalPropertyIgnoreAttributes(
415 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 // If setting the property on the boilerplate throws an
418 // exception, the exception is converted to an empty handle in
419 // the handle based operations. In that case, we need to
420 // convert back to an exception.
421 if (result.is_null()) return result;
422 }
423
424 // Transform to fast properties if necessary. For object literals with
425 // containing function literals we defer this operation until after all
426 // computed properties have been assigned so that we can generate
427 // constant function properties.
428 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000429 JSObject::TransformToFastProperties(
430 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000434}
435
436
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000437MaybeObject* TransitionElements(Handle<Object> object,
438 ElementsKind to_kind,
439 Isolate* isolate) {
440 HandleScope scope(isolate);
441 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
442 ElementsKind from_kind =
443 Handle<JSObject>::cast(object)->map()->elements_kind();
444 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
445 Handle<Object> result = JSObject::TransitionElementsKind(
446 Handle<JSObject>::cast(object), to_kind);
447 if (result.is_null()) return isolate->ThrowIllegalOperation();
448 return *result;
449 }
450 return isolate->ThrowIllegalOperation();
451}
452
453
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000454static const int kSmiOnlyLiteralMinimumLength = 1024;
455
456
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000457Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000459 Handle<FixedArray> literals,
460 Handle<FixedArray> elements) {
461 // Create the JSArray.
462 Handle<JSFunction> constructor(
463 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 Handle<JSArray> object =
465 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467 ElementsKind constant_elements_kind =
468 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
469 Handle<FixedArrayBase> constant_elements_values(
470 FixedArrayBase::cast(elements->get(1)));
471
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000472 Context* global_context = isolate->context()->global_context();
473 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
474 object->set_map(Map::cast(global_context->smi_js_array_map()));
475 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 object->set_map(Map::cast(global_context->double_js_array_map()));
477 } else {
478 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481 Handle<FixedArrayBase> copied_elements_values;
482 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
483 ASSERT(FLAG_smi_only_arrays);
484 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
485 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000486 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000487 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
488 constant_elements_kind == FAST_ELEMENTS);
489 const bool is_cow =
490 (constant_elements_values->map() ==
491 isolate->heap()->fixed_cow_array_map());
492 if (is_cow) {
493 copied_elements_values = constant_elements_values;
494#if DEBUG
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(copied_elements_values);
497 for (int i = 0; i < fixed_array_values->length(); i++) {
498 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
499 }
500#endif
501 } else {
502 Handle<FixedArray> fixed_array_values =
503 Handle<FixedArray>::cast(constant_elements_values);
504 Handle<FixedArray> fixed_array_values_copy =
505 isolate->factory()->CopyFixedArray(fixed_array_values);
506 copied_elements_values = fixed_array_values_copy;
507 for (int i = 0; i < fixed_array_values->length(); i++) {
508 Object* current = fixed_array_values->get(i);
509 if (current->IsFixedArray()) {
510 // The value contains the constant_properties of a
511 // simple object or array literal.
512 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
513 Handle<Object> result =
514 CreateLiteralBoilerplate(isolate, literals, fa);
515 if (result.is_null()) return result;
516 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000517 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000519 }
520 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000521 object->set_elements(*copied_elements_values);
522 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000523
524 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
525 // on or the object is larger than the threshold.
526 if (!FLAG_smi_only_arrays &&
527 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
528 if (object->GetElementsKind() != FAST_ELEMENTS) {
529 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
530 }
531 }
532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000533 return object;
534}
535
536
537static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 Handle<FixedArray> literals,
540 Handle<FixedArray> array) {
541 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000543 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000544 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return CreateObjectLiteralBoilerplate(isolate,
546 literals,
547 elements,
548 true,
549 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000550 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 return CreateObjectLiteralBoilerplate(isolate,
552 literals,
553 elements,
554 false,
555 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000556 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000557 return Runtime::CreateArrayLiteralBoilerplate(
558 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000559 default:
560 UNREACHABLE();
561 return Handle<Object>::null();
562 }
563}
564
565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000566RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000568 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000569 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000570 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000571 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000572 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
574 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateObjectLiteralBoilerplate(isolate,
580 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000581 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 should_have_fast_elements,
583 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 if (boilerplate.is_null()) return Failure::Exception();
585 // Update the functions literal and return the boilerplate.
586 literals->set(literals_index, *boilerplate);
587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000594 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000595 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000596 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
600 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601
602 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 Handle<Object> boilerplate(literals->get(literals_index), isolate);
604 if (*boilerplate == isolate->heap()->undefined_value()) {
605 boilerplate = CreateObjectLiteralBoilerplate(isolate,
606 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000607 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 should_have_fast_elements,
609 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000621 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000623 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000635}
636
637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000640 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000641 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000642 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000643 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644
645 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 Handle<Object> boilerplate(literals->get(literals_index), isolate);
647 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000648 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000649 boilerplate =
650 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 if (boilerplate.is_null()) return Failure::Exception();
652 // Update the functions literal and return the boilerplate.
653 literals->set(literals_index, *boilerplate);
654 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000655 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000657 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000658 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000660}
661
662
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000663RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
664 ASSERT(args.length() == 2);
665 Object* handler = args[0];
666 Object* prototype = args[1];
667 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000669 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
670}
671
672
lrn@chromium.org34e60782011-09-15 07:25:40 +0000673RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
674 ASSERT(args.length() == 4);
675 Object* handler = args[0];
676 Object* call_trap = args[1];
677 Object* construct_trap = args[2];
678 Object* prototype = args[3];
679 Object* used_prototype =
680 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
681 return isolate->heap()->AllocateJSFunctionProxy(
682 handler, call_trap, construct_trap, used_prototype);
683}
684
685
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
687 ASSERT(args.length() == 1);
688 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000689 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000690}
691
692
lrn@chromium.org34e60782011-09-15 07:25:40 +0000693RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
694 ASSERT(args.length() == 1);
695 Object* obj = args[0];
696 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
697}
698
699
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
701 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000702 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000703 return proxy->handler();
704}
705
706
lrn@chromium.org34e60782011-09-15 07:25:40 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
708 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000710 return proxy->call_trap();
711}
712
713
714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
715 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000716 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000717 return proxy->construct_trap();
718}
719
720
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
722 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000723 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000724 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000725 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000726}
727
728
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000729RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
730 HandleScope scope(isolate);
731 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000732 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
734 holder->set_table(*table);
735 return *holder;
736}
737
738
739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
740 HandleScope scope(isolate);
741 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000742 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000743 Handle<Object> key(args[1]);
744 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
745 table = ObjectHashSetAdd(table, key);
746 holder->set_table(*table);
747 return isolate->heap()->undefined_symbol();
748}
749
750
751RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
752 HandleScope scope(isolate);
753 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000754 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000755 Handle<Object> key(args[1]);
756 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
757 return isolate->heap()->ToBoolean(table->Contains(*key));
758}
759
760
761RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
762 HandleScope scope(isolate);
763 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000764 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000765 Handle<Object> key(args[1]);
766 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
767 table = ObjectHashSetRemove(table, key);
768 holder->set_table(*table);
769 return isolate->heap()->undefined_symbol();
770}
771
772
773RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
774 HandleScope scope(isolate);
775 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000776 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000777 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
778 holder->set_table(*table);
779 return *holder;
780}
781
782
783RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
784 HandleScope scope(isolate);
785 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000786 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000787 Handle<Object> key(args[1]);
788 return ObjectHashTable::cast(holder->table())->Lookup(*key);
789}
790
791
792RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
793 HandleScope scope(isolate);
794 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000795 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 Handle<Object> key(args[1]);
797 Handle<Object> value(args[2]);
798 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
799 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
800 holder->set_table(*new_table);
801 return *value;
802}
803
804
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000808 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000809 ASSERT(weakmap->map()->inobject_properties() == 0);
810 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
811 weakmap->set_table(*table);
812 weakmap->set_next(Smi::FromInt(0));
813 return *weakmap;
814}
815
816
817RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
818 NoHandleAllocation ha;
819 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000820 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
821 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000823}
824
825
826RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
827 HandleScope scope(isolate);
828 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000829 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
830 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000831 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000832 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000833 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
834 weakmap->set_table(*new_table);
835 return *value;
836}
837
838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000839RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 NoHandleAllocation ha;
841 ASSERT(args.length() == 1);
842 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844 return JSObject::cast(obj)->class_name();
845}
846
ager@chromium.org7c537e22008-10-16 08:43:32 +0000847
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000848RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
849 NoHandleAllocation ha;
850 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000851 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 Object* obj = input_obj;
853 // We don't expect access checks to be needed on JSProxy objects.
854 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000855 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000856 if (obj->IsAccessCheckNeeded() &&
857 !isolate->MayNamedAccess(JSObject::cast(obj),
858 isolate->heap()->Proto_symbol(),
859 v8::ACCESS_GET)) {
860 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
861 return isolate->heap()->undefined_value();
862 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000863 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000864 } while (obj->IsJSObject() &&
865 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 return obj;
867}
868
869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000870RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 NoHandleAllocation ha;
872 ASSERT(args.length() == 2);
873 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
874 Object* O = args[0];
875 Object* V = args[1];
876 while (true) {
877 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 if (prototype->IsNull()) return isolate->heap()->false_value();
879 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 V = prototype;
881 }
882}
883
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Recursively traverses hidden prototypes if property is not found
886static void GetOwnPropertyImplementation(JSObject* obj,
887 String* name,
888 LookupResult* result) {
889 obj->LocalLookupRealNamedProperty(name, result);
890
891 if (!result->IsProperty()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsJSObject() &&
894 JSObject::cast(proto)->map()->is_hidden_prototype())
895 GetOwnPropertyImplementation(JSObject::cast(proto),
896 name, result);
897 }
898}
899
900
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000901static bool CheckAccessException(LookupResult* result,
902 v8::AccessType access_type) {
903 if (result->type() == CALLBACKS) {
904 Object* callback = result->GetCallbackObject();
905 if (callback->IsAccessorInfo()) {
906 AccessorInfo* info = AccessorInfo::cast(callback);
907 bool can_access =
908 (access_type == v8::ACCESS_HAS &&
909 (info->all_can_read() || info->all_can_write())) ||
910 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
911 (access_type == v8::ACCESS_SET && info->all_can_write());
912 return can_access;
913 }
914 }
915
916 return false;
917}
918
919
920static bool CheckAccess(JSObject* obj,
921 String* name,
922 LookupResult* result,
923 v8::AccessType access_type) {
924 ASSERT(result->IsProperty());
925
926 JSObject* holder = result->holder();
927 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000929 while (true) {
930 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 // Access check callback denied the access, but some properties
933 // can have a special permissions which override callbacks descision
934 // (currently see v8::AccessControl).
935 break;
936 }
937
938 if (current == holder) {
939 return true;
940 }
941
942 current = JSObject::cast(current->GetPrototype());
943 }
944
945 // API callbacks can have per callback access exceptions.
946 switch (result->type()) {
947 case CALLBACKS: {
948 if (CheckAccessException(result, access_type)) {
949 return true;
950 }
951 break;
952 }
953 case INTERCEPTOR: {
954 // If the object has an interceptor, try real named properties.
955 // Overwrite the result to fetch the correct property later.
956 holder->LookupRealNamedProperty(name, result);
957 if (result->IsProperty()) {
958 if (CheckAccessException(result, access_type)) {
959 return true;
960 }
961 }
962 break;
963 }
964 default:
965 break;
966 }
967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000969 return false;
970}
971
972
973// TODO(1095): we should traverse hidden prototype hierachy as well.
974static bool CheckElementAccess(JSObject* obj,
975 uint32_t index,
976 v8::AccessType access_type) {
977 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000979 return false;
980 }
981
982 return true;
983}
984
985
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000986// Enumerator used as indices into the array returned from GetOwnProperty
987enum PropertyDescriptorIndices {
988 IS_ACCESSOR_INDEX,
989 VALUE_INDEX,
990 GETTER_INDEX,
991 SETTER_INDEX,
992 WRITABLE_INDEX,
993 ENUMERABLE_INDEX,
994 CONFIGURABLE_INDEX,
995 DESCRIPTOR_SIZE
996};
997
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000998
999static MaybeObject* GetOwnProperty(Isolate* isolate,
1000 Handle<JSObject> obj,
1001 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1004 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001005 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001006 // This could be an element.
1007 uint32_t index;
1008 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 switch (obj->HasLocalElement(index)) {
1010 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001012
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001013 case JSObject::STRING_CHARACTER_ELEMENT: {
1014 // Special handling of string objects according to ECMAScript 5
1015 // 15.5.5.2. Note that this might be a string object with elements
1016 // other than the actual string value. This is covered by the
1017 // subsequent cases.
1018 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1019 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001020 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001025 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001026 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001027 return *desc;
1028 }
1029
1030 case JSObject::INTERCEPTED_ELEMENT:
1031 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001033 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001035 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 elms->set(WRITABLE_INDEX, heap->true_value());
1037 elms->set(ENUMERABLE_INDEX, heap->true_value());
1038 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001039 return *desc;
1040 }
1041
1042 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 Handle<JSObject> holder = obj;
1044 if (obj->IsJSGlobalProxy()) {
1045 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001046 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001047 ASSERT(proto->IsJSGlobalObject());
1048 holder = Handle<JSObject>(JSObject::cast(proto));
1049 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001051 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001052 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001053 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001054 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001055 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001056 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001058 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001059 PropertyDetails details = dictionary->DetailsAt(entry);
1060 switch (details.type()) {
1061 case CALLBACKS: {
1062 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001063 AccessorPair* accessors =
1064 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001065 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001066 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001067 elms->set(GETTER_INDEX, accessors->SafeGet(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001068 }
1069 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001070 elms->set(SETTER_INDEX, accessors->SafeGet(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001071 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001072 break;
1073 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001075 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001077 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001078 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001079 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001081 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001082 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001083 default:
1084 UNREACHABLE();
1085 break;
1086 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1088 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001089 return *desc;
1090 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001091 }
1092 }
1093
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001094 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001095 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001097 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001099 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001100
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001101 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001103 }
1104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001107
1108 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001109 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001110
1111 if (is_js_accessor) {
1112 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001115 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001116 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001117 elms->set(GETTER_INDEX, accessors->SafeGet(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001118 }
1119 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001120 elms->set(SETTER_INDEX, accessors->SafeGet(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001121 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001122 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1124 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125
1126 PropertyAttributes attrs;
1127 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001128 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001129 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1130 if (!maybe_value->ToObject(&value)) return maybe_value;
1131 }
1132 elms->set(VALUE_INDEX, value);
1133 }
1134
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001135 return *desc;
1136}
1137
1138
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001139// Returns an array with the property description:
1140// if args[1] is not a property on args[0]
1141// returns undefined
1142// if args[1] is a data property on args[0]
1143// [false, value, Writeable, Enumerable, Configurable]
1144// if args[1] is an accessor on args[0]
1145// [true, GetFunction, SetFunction, Enumerable, Configurable]
1146RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1147 ASSERT(args.length() == 2);
1148 HandleScope scope(isolate);
1149 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1150 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1151 return GetOwnProperty(isolate, obj, name);
1152}
1153
1154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001156 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001157 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001158 return obj->PreventExtensions();
1159}
1160
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001162RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001163 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001164 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001165 if (obj->IsJSGlobalProxy()) {
1166 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001168 ASSERT(proto->IsJSGlobalObject());
1169 obj = JSObject::cast(proto);
1170 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001171 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001172}
1173
1174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001175RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001176 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001178 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1179 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1180 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001181 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1182 if (result.is_null()) return Failure::Exception();
1183 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184}
1185
1186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001187RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001190 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001191 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192}
1193
1194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001195RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 ASSERT(args.length() == 1);
1197 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001198 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001199 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200}
1201
1202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001203RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001205 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1206 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001207 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1208 InstanceType type = templ->map()->instance_type();
1209 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1210 type == OBJECT_TEMPLATE_INFO_TYPE);
1211 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001212 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001213 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1214 } else {
1215 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1216 }
1217 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218}
1219
1220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001221RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001223 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001224 Map* old_map = object->map();
1225 bool needs_access_checks = old_map->is_access_check_needed();
1226 if (needs_access_checks) {
1227 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001228 Object* new_map;
1229 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1230 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1231 }
ager@chromium.org32912102009-01-16 10:38:43 +00001232
1233 Map::cast(new_map)->set_is_access_check_needed(false);
1234 object->set_map(Map::cast(new_map));
1235 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001236 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001237}
1238
1239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001240RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001241 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001242 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001243 Map* old_map = object->map();
1244 if (!old_map->is_access_check_needed()) {
1245 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001246 Object* new_map;
1247 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1248 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1249 }
ager@chromium.org32912102009-01-16 10:38:43 +00001250
1251 Map::cast(new_map)->set_is_access_check_needed(true);
1252 object->set_map(Map::cast(new_map));
1253 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001255}
1256
1257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258static Failure* ThrowRedeclarationError(Isolate* isolate,
1259 const char* type,
1260 Handle<String> name) {
1261 HandleScope scope(isolate);
1262 Handle<Object> type_handle =
1263 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 Handle<Object> args[2] = { type_handle, name };
1265 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001266 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1267 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268}
1269
1270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001271RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001272 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001273 HandleScope scope(isolate);
1274 Handle<GlobalObject> global = Handle<GlobalObject>(
1275 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276
ager@chromium.org3811b432009-10-28 14:53:37 +00001277 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001278 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001279 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 // Traverse the name/value pairs and set the properties.
1282 int length = pairs->length();
1283 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001284 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001286 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287
1288 // We have to declare a global const property. To capture we only
1289 // assign to it when evaluating the assignment for "const x =
1290 // <expr>" the initial value is the hole.
1291 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001292 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 if (value->IsUndefined() || is_const_property) {
1294 // Lookup the property in the global object, and don't set the
1295 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001296 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 global->Lookup(*name, &lookup);
1298 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001299 // We found an existing property. Unless it was an interceptor
1300 // that claims the property is absent, skip this declaration.
1301 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302 continue;
1303 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001304 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1305 if (attributes != ABSENT) {
1306 continue;
1307 }
1308 // Fall-through and introduce the absent property by using
1309 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 }
1311 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001312 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001314 Handle<SharedFunctionInfo> shared =
1315 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001317 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1318 context,
1319 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 value = function;
1321 }
1322
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001323 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 global->LocalLookup(*name, &lookup);
1325
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001326 // Compute the property attributes. According to ECMA-262, section
1327 // 13, page 71, the property must be read-only and
1328 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1329 // property as read-only, so we don't either.
1330 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001331 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001332 attr |= DONT_DELETE;
1333 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001334 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001335 if (is_const_property || (is_native && is_function_declaration)) {
1336 attr |= READ_ONLY;
1337 }
1338
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001339 // Safari does not allow the invocation of callback setters for
1340 // function declarations. To mimic this behavior, we do not allow
1341 // the invocation of setters for function values. This makes a
1342 // difference for global functions with the same names as event
1343 // handlers such as "function onload() {}". Firefox does call the
1344 // onload setter in those case and Safari does not. We follow
1345 // Safari for compatibility.
1346 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001347 // Do not change DONT_DELETE to false from true.
1348 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001349 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001351 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1352
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001353 RETURN_IF_EMPTY_HANDLE(
1354 isolate,
1355 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1356 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001358 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1359 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1360 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001361 RETURN_IF_EMPTY_HANDLE(
1362 isolate,
1363 JSReceiver::SetProperty(global, name, value,
1364 static_cast<PropertyAttributes>(attr),
1365 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 }
1367 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001369 ASSERT(!isolate->has_pending_exception());
1370 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371}
1372
1373
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001374RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001376 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 // Declarations are always made in a function or global context. In the
1379 // case of eval code, the context passed is the context of the caller,
1380 // which may be some nested context and not the declaration context.
1381 RUNTIME_ASSERT(args[0]->IsContext());
1382 Handle<Context> context(Context::cast(args[0])->declaration_context());
1383
ager@chromium.org7c537e22008-10-16 08:43:32 +00001384 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001385 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001386 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389 int index;
1390 PropertyAttributes attributes;
1391 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001392 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001393 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001394 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395
1396 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001397 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1399 // Functions are not read-only.
1400 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1401 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 }
1404
1405 // Initialize it if necessary.
1406 if (*initial_value != NULL) {
1407 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001408 ASSERT(holder.is_identical_to(context));
1409 if (((attributes & READ_ONLY) == 0) ||
1410 context->get(index)->IsTheHole()) {
1411 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 }
1413 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001414 // Slow case: The property is in the context extension object of a
1415 // function context or the global object of a global context.
1416 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001417 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001419 JSReceiver::SetProperty(object, name, initial_value, mode,
1420 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421 }
1422 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001425 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001426 // "declared" in the function context's extension context or as a
1427 // property of the the global object.
1428 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001429 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001430 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001431 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001432 // Context extension objects are allocated lazily.
1433 ASSERT(context->IsFunctionContext());
1434 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001435 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001437 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001438 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439
ager@chromium.org7c537e22008-10-16 08:43:32 +00001440 // Declare the property by setting it to the initial value if provided,
1441 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1442 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001443 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001445 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001446 // Declaring a const context slot is a conflicting declaration if
1447 // there is a callback with that name in a prototype. It is
1448 // allowed to introduce const variables in
1449 // JSContextExtensionObjects. They are treated specially in
1450 // SetProperty and no setters are invoked for those since they are
1451 // not real JSObjects.
1452 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001453 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001454 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001455 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001456 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001458 }
1459 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001460 RETURN_IF_EMPTY_HANDLE(
1461 isolate,
1462 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001463 }
1464
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466}
1467
1468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001469RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001471 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001472 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001473 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474
1475 // Determine if we need to assign to the variable if it already
1476 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1478 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001480 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001481 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001482 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001483 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1484 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1485 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486
1487 // According to ECMA-262, section 12.2, page 62, the property must
1488 // not be deletable.
1489 PropertyAttributes attributes = DONT_DELETE;
1490
1491 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001492 // there, there is a property with this name in the prototype chain.
1493 // We follow Safari and Firefox behavior and only set the property
1494 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001495 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001496 // Note that objects can have hidden prototypes, so we need to traverse
1497 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 while (object->IsJSObject() &&
1501 JSObject::cast(object)->map()->is_hidden_prototype()) {
1502 JSObject* raw_holder = JSObject::cast(object);
1503 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001504 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001505 HandleScope handle_scope(isolate);
1506 Handle<JSObject> holder(raw_holder);
1507 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1508 // Update the raw pointer in case it's changed due to GC.
1509 raw_holder = *holder;
1510 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1511 // Found an interceptor that's not read only.
1512 if (assign) {
1513 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001514 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 } else {
1516 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001517 }
1518 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001519 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 }
1522
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001525 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001526 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001528 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529}
1530
1531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001532RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001533 // All constants are declared with an initial value. The name
1534 // of the constant is the first argument and the initial value
1535 // is the second.
1536 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001537 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538 Handle<Object> value = args.at<Object>(1);
1539
1540 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542
1543 // According to ECMA-262, section 12.2, page 62, the property must
1544 // not be deletable. Since it's a const, it must be READ_ONLY too.
1545 PropertyAttributes attributes =
1546 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1547
1548 // Lookup the property locally in the global object. If it isn't
1549 // there, we add the property and take special precautions to always
1550 // add it as a local property even in case of callbacks in the
1551 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001552 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001553 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 global->LocalLookup(*name, &lookup);
1555 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001556 return global->SetLocalPropertyIgnoreAttributes(*name,
1557 *value,
1558 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559 }
1560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001564 HandleScope handle_scope(isolate);
1565 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001567 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 // property through an interceptor and only do it if it's
1569 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001570 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001571 RETURN_IF_EMPTY_HANDLE(
1572 isolate,
1573 JSReceiver::SetProperty(global, name, value, attributes,
1574 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 return *value;
1576 }
1577
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001578 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579 // constant. For now, we determine this by checking if the
1580 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582 PropertyType type = lookup.type();
1583 if (type == FIELD) {
1584 FixedArray* properties = global->properties();
1585 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001586 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587 properties->set(index, *value);
1588 }
1589 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001590 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1591 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001592 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593 }
1594 } else {
1595 // Ignore re-initialization of constants that have already been
1596 // assigned a function value.
1597 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1598 }
1599
1600 // Use the set value as the result of the operation.
1601 return *value;
1602}
1603
1604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001605RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001606 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607 ASSERT(args.length() == 3);
1608
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001609 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001612 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001613 RUNTIME_ASSERT(args[1]->IsContext());
1614 Handle<Context> context(Context::cast(args[1])->declaration_context());
1615
1616 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617
1618 int index;
1619 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001620 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001621 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001622 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001623 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001626 ASSERT(holder->IsContext());
1627 // Property was found in a context. Perform the assignment if we
1628 // found some non-constant or an uninitialized constant.
1629 Handle<Context> context = Handle<Context>::cast(holder);
1630 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1631 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 }
1633 return *value;
1634 }
1635
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 // The property could not be found, we introduce it as a property of the
1637 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001638 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001639 Handle<JSObject> global = Handle<JSObject>(
1640 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001641 // Strict mode not needed (const disallowed in strict mode).
1642 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001644 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001645 return *value;
1646 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001648 // The property was present in some function's context extension object,
1649 // as a property on the subject of a with, or as a property of the global
1650 // object.
1651 //
1652 // In most situations, eval-introduced consts should still be present in
1653 // the context extension object. However, because declaration and
1654 // initialization are separate, the property might have been deleted
1655 // before we reach the initialization point.
1656 //
1657 // Example:
1658 //
1659 // function f() { eval("delete x; const x;"); }
1660 //
1661 // In that case, the initialization behaves like a normal assignment.
1662 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001664 if (*object == context->extension()) {
1665 // This is the property that was introduced by the const declaration.
1666 // Set it if it hasn't been set before. NOTE: We cannot use
1667 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001668 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001669 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001670 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001671 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1672
1673 PropertyType type = lookup.type();
1674 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001675 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001676 int index = lookup.GetFieldIndex();
1677 if (properties->get(index)->IsTheHole()) {
1678 properties->set(index, *value);
1679 }
1680 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001681 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1682 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001683 }
1684 } else {
1685 // We should not reach here. Any real, named property should be
1686 // either a field or a dictionary slot.
1687 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688 }
1689 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001690 // The property was found on some other object. Set it if it is not a
1691 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001692 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001693 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001694 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001695 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001696 JSReceiver::SetProperty(object, name, value, attributes,
1697 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001698 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701 return *value;
1702}
1703
1704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001705RUNTIME_FUNCTION(MaybeObject*,
1706 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001708 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001709 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001710 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001711 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001712 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001713 }
1714 return *object;
1715}
1716
1717
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001718RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001719 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001720 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001721 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1722 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001723 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001724 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001725 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001726 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001727 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001728 RUNTIME_ASSERT(index >= 0);
1729 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001731 Handle<Object> result = RegExpImpl::Exec(regexp,
1732 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001733 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001734 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001735 if (result.is_null()) return Failure::Exception();
1736 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001741 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001742 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001743 if (elements_count < 0 ||
1744 elements_count > FixedArray::kMaxLength ||
1745 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001748 Object* new_object;
1749 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001750 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1752 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001753 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1755 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001756 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1757 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001758 {
1759 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001761 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001762 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001763 }
1764 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001766 array->set_elements(elements);
1767 array->set_length(Smi::FromInt(elements_count));
1768 // Write in-object properties after the length of the array.
1769 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1770 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1771 return array;
1772}
1773
1774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001775RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001776 AssertNoAllocation no_alloc;
1777 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001778 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1779 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780
1781 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001782 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001783
1784 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786
1787 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001789
1790 Map* map = regexp->map();
1791 Object* constructor = map->constructor();
1792 if (constructor->IsJSFunction() &&
1793 JSFunction::cast(constructor)->initial_map() == map) {
1794 // If we still have the original map, set in-object properties directly.
1795 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001796 // Both true and false are immovable immortal objects so no need for write
1797 // barrier.
1798 regexp->InObjectPropertyAtPut(
1799 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1800 regexp->InObjectPropertyAtPut(
1801 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1802 regexp->InObjectPropertyAtPut(
1803 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001804 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1805 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001806 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001807 return regexp;
1808 }
1809
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001811 PropertyAttributes final =
1812 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1813 PropertyAttributes writable =
1814 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001815 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001816 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001818 source,
1819 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001820 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001821 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001822 global,
1823 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001824 ASSERT(!result->IsFailure());
1825 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001827 ignoreCase,
1828 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001829 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001830 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001831 multiline,
1832 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001833 ASSERT(!result->IsFailure());
1834 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001835 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001836 Smi::FromInt(0),
1837 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001838 ASSERT(!result->IsFailure());
1839 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001840 return regexp;
1841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001845 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001846 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001847 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001848 // This is necessary to enable fast checks for absence of elements
1849 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001850 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001851 return Smi::FromInt(0);
1852}
1853
1854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1856 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001857 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001858 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1860 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1861 Handle<JSFunction> optimized =
1862 isolate->factory()->NewFunction(key,
1863 JS_OBJECT_TYPE,
1864 JSObject::kHeaderSize,
1865 code,
1866 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001867 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001868 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001869 return optimized;
1870}
1871
1872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001873RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001874 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001875 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001876 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001877
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001878 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1879 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1880 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1881 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1882 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1883 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1884 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001885
1886 return *holder;
1887}
1888
1889
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001890RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001891 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001892 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001893
1894 if (!callable->IsJSFunction()) {
1895 HandleScope scope(isolate);
1896 bool threw = false;
1897 Handle<Object> delegate =
1898 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1899 if (threw) return Failure::Exception();
1900 callable = JSFunction::cast(*delegate);
1901 }
1902 JSFunction* function = JSFunction::cast(callable);
1903
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001904 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001905 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001906 return isolate->heap()->undefined_value();
1907 }
1908 // Returns undefined for strict or native functions, or
1909 // the associated global receiver for "normal" functions.
1910
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001912 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001913 return global_context->global()->global_receiver();
1914}
1915
1916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001917RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001918 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001920 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001921 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001922 Handle<String> pattern = args.at<String>(2);
1923 Handle<String> flags = args.at<String>(3);
1924
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001925 // Get the RegExp function from the context in the literals array.
1926 // This is the RegExp function from the context in which the
1927 // function was created. We do not use the RegExp function from the
1928 // current global context because this might be the RegExp function
1929 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001930 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001931 Handle<JSFunction>(
1932 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 // Compute the regular expression literal.
1934 bool has_pending_exception;
1935 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001936 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1937 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001939 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001940 return Failure::Exception();
1941 }
1942 literals->set(index, *regexp);
1943 return *regexp;
1944}
1945
1946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001951 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001952 return f->shared()->name();
1953}
1954
1955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001957 NoHandleAllocation ha;
1958 ASSERT(args.length() == 2);
1959
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001960 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1961 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001962 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001963 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001964}
1965
1966
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001967RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1968 NoHandleAllocation ha;
1969 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001970 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001971 return isolate->heap()->ToBoolean(
1972 f->shared()->name_should_print_as_anonymous());
1973}
1974
1975
1976RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1977 NoHandleAllocation ha;
1978 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001979 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001980 f->shared()->set_name_should_print_as_anonymous(true);
1981 return isolate->heap()->undefined_value();
1982}
1983
1984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001985RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001986 NoHandleAllocation ha;
1987 ASSERT(args.length() == 1);
1988
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001989 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 Object* obj = f->RemovePrototype();
1991 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001992
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001993 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001994}
1995
1996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001997RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001998 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 ASSERT(args.length() == 1);
2000
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002001 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2003 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002004
2005 return *GetScriptWrapper(Handle<Script>::cast(script));
2006}
2007
2008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002010 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002011 ASSERT(args.length() == 1);
2012
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002013 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002014 Handle<SharedFunctionInfo> shared(f->shared());
2015 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020 NoHandleAllocation ha;
2021 ASSERT(args.length() == 1);
2022
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002023 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002024 int pos = fun->shared()->start_position();
2025 return Smi::FromInt(pos);
2026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002030 ASSERT(args.length() == 2);
2031
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002032 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002033 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2034
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002035 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2036
2037 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002038 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002039}
2040
2041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002042RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043 NoHandleAllocation ha;
2044 ASSERT(args.length() == 2);
2045
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002046 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2047 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002048 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002049 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050}
2051
2052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002053RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054 NoHandleAllocation ha;
2055 ASSERT(args.length() == 2);
2056
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002057 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2058 CONVERT_SMI_ARG_CHECKED(length, 1);
2059 fun->shared()->set_length(length);
2060 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002061}
2062
2063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002064RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002065 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002066 ASSERT(args.length() == 2);
2067
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002068 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002069 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002070 Object* obj;
2071 { MaybeObject* maybe_obj =
2072 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2073 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2074 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075 return args[0]; // return TOS
2076}
2077
2078
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002079RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2080 NoHandleAllocation ha;
2081 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002082 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002083
2084 MaybeObject* maybe_name =
2085 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2086 String* name;
2087 if (!maybe_name->To(&name)) return maybe_name;
2088
2089 if (function->HasFastProperties()) {
2090 // Construct a new field descriptor with updated attributes.
2091 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2092 int index = instance_desc->Search(name);
2093 ASSERT(index != DescriptorArray::kNotFound);
2094 PropertyDetails details(instance_desc->GetDetails(index));
2095 CallbacksDescriptor new_desc(name,
2096 instance_desc->GetValue(index),
2097 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2098 details.index());
2099 // Construct a new field descriptors array containing the new descriptor.
2100 Object* descriptors_unchecked;
2101 { MaybeObject* maybe_descriptors_unchecked =
2102 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2103 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2104 return maybe_descriptors_unchecked;
2105 }
2106 }
2107 DescriptorArray* new_descriptors =
2108 DescriptorArray::cast(descriptors_unchecked);
2109 // Create a new map featuring the new field descriptors array.
2110 Object* map_unchecked;
2111 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2112 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2113 return maybe_map_unchecked;
2114 }
2115 }
2116 Map* new_map = Map::cast(map_unchecked);
2117 new_map->set_instance_descriptors(new_descriptors);
2118 function->set_map(new_map);
2119 } else { // Dictionary properties.
2120 // Directly manipulate the property details.
2121 int entry = function->property_dictionary()->FindEntry(name);
2122 ASSERT(entry != StringDictionary::kNotFound);
2123 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2124 PropertyDetails new_details(
2125 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2126 details.type(),
2127 details.index());
2128 function->property_dictionary()->DetailsAtPut(entry, new_details);
2129 }
2130 return function;
2131}
2132
2133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002134RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002135 NoHandleAllocation ha;
2136 ASSERT(args.length() == 1);
2137
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002138 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002139 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002140}
2141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002143RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002144 NoHandleAllocation ha;
2145 ASSERT(args.length() == 1);
2146
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002147 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002148 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002149}
2150
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002152RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002153 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 ASSERT(args.length() == 2);
2155
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002156 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002157 Handle<Object> code = args.at<Object>(1);
2158
2159 Handle<Context> context(target->context());
2160
2161 if (!code->IsNull()) {
2162 RUNTIME_ASSERT(code->IsJSFunction());
2163 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002164 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002165
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002166 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 return Failure::Exception();
2168 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002169 // Since we don't store the source for this we should never
2170 // optimize this.
2171 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002172 // Set the code, scope info, formal parameter count,
2173 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002174 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002175 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002176 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002177 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002179 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002180 // Set the source code of the target function to undefined.
2181 // SetCode is only used for built-in constructors like String,
2182 // Array, and Object, and some web code
2183 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002184 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002185 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002186 // Clear the optimization hints related to the compiled code as these are no
2187 // longer valid when the code is overwritten.
2188 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002189 context = Handle<Context>(fun->context());
2190
2191 // Make sure we get a fresh copy of the literal vector to avoid
2192 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002193 int number_of_literals = fun->NumberOfLiterals();
2194 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002195 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002196 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002197 // Insert the object, regexp and array functions in the literals
2198 // array prefix. These are the functions that will be used when
2199 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002200 literals->set(JSFunction::kLiteralGlobalContextIndex,
2201 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002203 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002205
2206 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2207 isolate->logger()->LogExistingFunction(
2208 shared, Handle<Code>(shared->code()));
2209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002210 }
2211
2212 target->set_context(*context);
2213 return *target;
2214}
2215
2216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002217RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002218 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002219 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002220 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002221 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002222 RUNTIME_ASSERT(num >= 0);
2223 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002224 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002225}
2226
2227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2229 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002230 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002231 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002232 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002233 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002234 }
2235 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002236 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002237}
2238
2239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002240RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002241 NoHandleAllocation ha;
2242 ASSERT(args.length() == 2);
2243
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002244 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002245 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002246 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002248 uint32_t i = 0;
2249 if (index->IsSmi()) {
2250 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002251 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002252 i = value;
2253 } else {
2254 ASSERT(index->IsHeapNumber());
2255 double value = HeapNumber::cast(index)->value();
2256 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002257 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002258
2259 // Flatten the string. If someone wants to get a char at an index
2260 // in a cons string, it is likely that more indices will be
2261 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002262 Object* flat;
2263 { MaybeObject* maybe_flat = subject->TryFlatten();
2264 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2265 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002266 subject = String::cast(flat);
2267
2268 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002269 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002270 }
2271
2272 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002273}
2274
2275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002276RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002277 NoHandleAllocation ha;
2278 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002279 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280}
2281
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282
2283class FixedArrayBuilder {
2284 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2286 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002287 length_(0),
2288 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002289 // Require a non-zero initial size. Ensures that doubling the size to
2290 // extend the array will work.
2291 ASSERT(initial_capacity > 0);
2292 }
2293
2294 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2295 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002296 length_(0),
2297 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002298 // Require a non-zero initial size. Ensures that doubling the size to
2299 // extend the array will work.
2300 ASSERT(backing_store->length() > 0);
2301 }
2302
2303 bool HasCapacity(int elements) {
2304 int length = array_->length();
2305 int required_length = length_ + elements;
2306 return (length >= required_length);
2307 }
2308
2309 void EnsureCapacity(int elements) {
2310 int length = array_->length();
2311 int required_length = length_ + elements;
2312 if (length < required_length) {
2313 int new_length = length;
2314 do {
2315 new_length *= 2;
2316 } while (new_length < required_length);
2317 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002318 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 array_->CopyTo(0, *extended_array, 0, length_);
2320 array_ = extended_array;
2321 }
2322 }
2323
2324 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002325 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002326 ASSERT(length_ < capacity());
2327 array_->set(length_, value);
2328 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002329 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002330 }
2331
2332 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002333 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002334 ASSERT(length_ < capacity());
2335 array_->set(length_, value);
2336 length_++;
2337 }
2338
2339 Handle<FixedArray> array() {
2340 return array_;
2341 }
2342
2343 int length() {
2344 return length_;
2345 }
2346
2347 int capacity() {
2348 return array_->length();
2349 }
2350
2351 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002352 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002353 result_array->set_length(Smi::FromInt(length_));
2354 return result_array;
2355 }
2356
2357 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002358 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002359 target_array->set_length(Smi::FromInt(length_));
2360 return target_array;
2361 }
2362
2363 private:
2364 Handle<FixedArray> array_;
2365 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002366 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002367};
2368
2369
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002370// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002371const int kStringBuilderConcatHelperLengthBits = 11;
2372const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002373
2374template <typename schar>
2375static inline void StringBuilderConcatHelper(String*,
2376 schar*,
2377 FixedArray*,
2378 int);
2379
lrn@chromium.org25156de2010-04-06 13:10:27 +00002380typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2381 StringBuilderSubstringLength;
2382typedef BitField<int,
2383 kStringBuilderConcatHelperLengthBits,
2384 kStringBuilderConcatHelperPositionBits>
2385 StringBuilderSubstringPosition;
2386
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002387
2388class ReplacementStringBuilder {
2389 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002390 ReplacementStringBuilder(Heap* heap,
2391 Handle<String> subject,
2392 int estimated_part_count)
2393 : heap_(heap),
2394 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002395 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002396 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002397 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398 // Require a non-zero initial size. Ensures that doubling the size to
2399 // extend the array will work.
2400 ASSERT(estimated_part_count > 0);
2401 }
2402
lrn@chromium.org25156de2010-04-06 13:10:27 +00002403 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2404 int from,
2405 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 ASSERT(from >= 0);
2407 int length = to - from;
2408 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002409 if (StringBuilderSubstringLength::is_valid(length) &&
2410 StringBuilderSubstringPosition::is_valid(from)) {
2411 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2412 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002414 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002415 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 builder->Add(Smi::FromInt(-length));
2417 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002418 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002419 }
2420
2421
2422 void EnsureCapacity(int elements) {
2423 array_builder_.EnsureCapacity(elements);
2424 }
2425
2426
2427 void AddSubjectSlice(int from, int to) {
2428 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002429 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 }
2431
2432
2433 void AddString(Handle<String> string) {
2434 int length = string->length();
2435 ASSERT(length > 0);
2436 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002437 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438 is_ascii_ = false;
2439 }
2440 IncrementCharacterCount(length);
2441 }
2442
2443
2444 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002445 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002446 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002447 }
2448
2449 Handle<String> joined_string;
2450 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002451 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 char* char_buffer = seq->GetChars();
2454 StringBuilderConcatHelper(*subject_,
2455 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002456 *array_builder_.array(),
2457 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002458 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 } else {
2460 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 uc16* char_buffer = seq->GetChars();
2464 StringBuilderConcatHelper(*subject_,
2465 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 *array_builder_.array(),
2467 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002468 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 }
2470 return joined_string;
2471 }
2472
2473
2474 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002475 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 V8::FatalProcessOutOfMemory("String.replace result too large.");
2477 }
2478 character_count_ += by;
2479 }
2480
lrn@chromium.org25156de2010-04-06 13:10:27 +00002481 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002482 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002483 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002484
lrn@chromium.org25156de2010-04-06 13:10:27 +00002485 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002486 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2487 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002488 }
2489
2490
ager@chromium.org04921a82011-06-27 13:21:41 +00002491 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2492 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 }
2494
2495
2496 void AddElement(Object* element) {
2497 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002498 ASSERT(array_builder_.capacity() > array_builder_.length());
2499 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002500 }
2501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002502 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002503 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002504 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 int character_count_;
2506 bool is_ascii_;
2507};
2508
2509
2510class CompiledReplacement {
2511 public:
2512 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002513 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514
2515 void Compile(Handle<String> replacement,
2516 int capture_count,
2517 int subject_length);
2518
2519 void Apply(ReplacementStringBuilder* builder,
2520 int match_from,
2521 int match_to,
2522 Handle<JSArray> last_match_info);
2523
2524 // Number of distinct parts of the replacement pattern.
2525 int parts() {
2526 return parts_.length();
2527 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002528
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002529 bool simple_hint() {
2530 return simple_hint_;
2531 }
2532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002533 private:
2534 enum PartType {
2535 SUBJECT_PREFIX = 1,
2536 SUBJECT_SUFFIX,
2537 SUBJECT_CAPTURE,
2538 REPLACEMENT_SUBSTRING,
2539 REPLACEMENT_STRING,
2540
2541 NUMBER_OF_PART_TYPES
2542 };
2543
2544 struct ReplacementPart {
2545 static inline ReplacementPart SubjectMatch() {
2546 return ReplacementPart(SUBJECT_CAPTURE, 0);
2547 }
2548 static inline ReplacementPart SubjectCapture(int capture_index) {
2549 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2550 }
2551 static inline ReplacementPart SubjectPrefix() {
2552 return ReplacementPart(SUBJECT_PREFIX, 0);
2553 }
2554 static inline ReplacementPart SubjectSuffix(int subject_length) {
2555 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2556 }
2557 static inline ReplacementPart ReplacementString() {
2558 return ReplacementPart(REPLACEMENT_STRING, 0);
2559 }
2560 static inline ReplacementPart ReplacementSubString(int from, int to) {
2561 ASSERT(from >= 0);
2562 ASSERT(to > from);
2563 return ReplacementPart(-from, to);
2564 }
2565
2566 // If tag <= 0 then it is the negation of a start index of a substring of
2567 // the replacement pattern, otherwise it's a value from PartType.
2568 ReplacementPart(int tag, int data)
2569 : tag(tag), data(data) {
2570 // Must be non-positive or a PartType value.
2571 ASSERT(tag < NUMBER_OF_PART_TYPES);
2572 }
2573 // Either a value of PartType or a non-positive number that is
2574 // the negation of an index into the replacement string.
2575 int tag;
2576 // The data value's interpretation depends on the value of tag:
2577 // tag == SUBJECT_PREFIX ||
2578 // tag == SUBJECT_SUFFIX: data is unused.
2579 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2580 // tag == REPLACEMENT_SUBSTRING ||
2581 // tag == REPLACEMENT_STRING: data is index into array of substrings
2582 // of the replacement string.
2583 // tag <= 0: Temporary representation of the substring of the replacement
2584 // string ranging over -tag .. data.
2585 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2586 // substring objects.
2587 int data;
2588 };
2589
2590 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002591 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002592 Vector<Char> characters,
2593 int capture_count,
2594 int subject_length) {
2595 int length = characters.length();
2596 int last = 0;
2597 for (int i = 0; i < length; i++) {
2598 Char c = characters[i];
2599 if (c == '$') {
2600 int next_index = i + 1;
2601 if (next_index == length) { // No next character!
2602 break;
2603 }
2604 Char c2 = characters[next_index];
2605 switch (c2) {
2606 case '$':
2607 if (i > last) {
2608 // There is a substring before. Include the first "$".
2609 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2610 last = next_index + 1; // Continue after the second "$".
2611 } else {
2612 // Let the next substring start with the second "$".
2613 last = next_index;
2614 }
2615 i = next_index;
2616 break;
2617 case '`':
2618 if (i > last) {
2619 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2620 }
2621 parts->Add(ReplacementPart::SubjectPrefix());
2622 i = next_index;
2623 last = i + 1;
2624 break;
2625 case '\'':
2626 if (i > last) {
2627 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2628 }
2629 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2630 i = next_index;
2631 last = i + 1;
2632 break;
2633 case '&':
2634 if (i > last) {
2635 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2636 }
2637 parts->Add(ReplacementPart::SubjectMatch());
2638 i = next_index;
2639 last = i + 1;
2640 break;
2641 case '0':
2642 case '1':
2643 case '2':
2644 case '3':
2645 case '4':
2646 case '5':
2647 case '6':
2648 case '7':
2649 case '8':
2650 case '9': {
2651 int capture_ref = c2 - '0';
2652 if (capture_ref > capture_count) {
2653 i = next_index;
2654 continue;
2655 }
2656 int second_digit_index = next_index + 1;
2657 if (second_digit_index < length) {
2658 // Peek ahead to see if we have two digits.
2659 Char c3 = characters[second_digit_index];
2660 if ('0' <= c3 && c3 <= '9') { // Double digits.
2661 int double_digit_ref = capture_ref * 10 + c3 - '0';
2662 if (double_digit_ref <= capture_count) {
2663 next_index = second_digit_index;
2664 capture_ref = double_digit_ref;
2665 }
2666 }
2667 }
2668 if (capture_ref > 0) {
2669 if (i > last) {
2670 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2671 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002672 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002673 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2674 last = next_index + 1;
2675 }
2676 i = next_index;
2677 break;
2678 }
2679 default:
2680 i = next_index;
2681 break;
2682 }
2683 }
2684 }
2685 if (length > last) {
2686 if (last == 0) {
2687 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002688 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002689 } else {
2690 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2691 }
2692 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002693 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002694 }
2695
2696 ZoneList<ReplacementPart> parts_;
2697 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002698 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699};
2700
2701
2702void CompiledReplacement::Compile(Handle<String> replacement,
2703 int capture_count,
2704 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002705 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002706 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002707 String::FlatContent content = replacement->GetFlatContent();
2708 ASSERT(content.IsFlat());
2709 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002710 simple_hint_ = ParseReplacementPattern(&parts_,
2711 content.ToAsciiVector(),
2712 capture_count,
2713 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002714 } else {
2715 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002716 simple_hint_ = ParseReplacementPattern(&parts_,
2717 content.ToUC16Vector(),
2718 capture_count,
2719 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002720 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002721 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002722 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002723 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 int substring_index = 0;
2725 for (int i = 0, n = parts_.length(); i < n; i++) {
2726 int tag = parts_[i].tag;
2727 if (tag <= 0) { // A replacement string slice.
2728 int from = -tag;
2729 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002730 replacement_substrings_.Add(
2731 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002732 parts_[i].tag = REPLACEMENT_SUBSTRING;
2733 parts_[i].data = substring_index;
2734 substring_index++;
2735 } else if (tag == REPLACEMENT_STRING) {
2736 replacement_substrings_.Add(replacement);
2737 parts_[i].data = substring_index;
2738 substring_index++;
2739 }
2740 }
2741}
2742
2743
2744void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2745 int match_from,
2746 int match_to,
2747 Handle<JSArray> last_match_info) {
2748 for (int i = 0, n = parts_.length(); i < n; i++) {
2749 ReplacementPart part = parts_[i];
2750 switch (part.tag) {
2751 case SUBJECT_PREFIX:
2752 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2753 break;
2754 case SUBJECT_SUFFIX: {
2755 int subject_length = part.data;
2756 if (match_to < subject_length) {
2757 builder->AddSubjectSlice(match_to, subject_length);
2758 }
2759 break;
2760 }
2761 case SUBJECT_CAPTURE: {
2762 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002763 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002764 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2765 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2766 if (from >= 0 && to > from) {
2767 builder->AddSubjectSlice(from, to);
2768 }
2769 break;
2770 }
2771 case REPLACEMENT_SUBSTRING:
2772 case REPLACEMENT_STRING:
2773 builder->AddString(replacement_substrings_[part.data]);
2774 break;
2775 default:
2776 UNREACHABLE();
2777 }
2778 }
2779}
2780
2781
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002782void FindAsciiStringIndices(Vector<const char> subject,
2783 char pattern,
2784 ZoneList<int>* indices,
2785 unsigned int limit) {
2786 ASSERT(limit > 0);
2787 // Collect indices of pattern in subject using memchr.
2788 // Stop after finding at most limit values.
2789 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2790 const char* subject_end = subject_start + subject.length();
2791 const char* pos = subject_start;
2792 while (limit > 0) {
2793 pos = reinterpret_cast<const char*>(
2794 memchr(pos, pattern, subject_end - pos));
2795 if (pos == NULL) return;
2796 indices->Add(static_cast<int>(pos - subject_start));
2797 pos++;
2798 limit--;
2799 }
2800}
2801
2802
2803template <typename SubjectChar, typename PatternChar>
2804void FindStringIndices(Isolate* isolate,
2805 Vector<const SubjectChar> subject,
2806 Vector<const PatternChar> pattern,
2807 ZoneList<int>* indices,
2808 unsigned int limit) {
2809 ASSERT(limit > 0);
2810 // Collect indices of pattern in subject.
2811 // Stop after finding at most limit values.
2812 int pattern_length = pattern.length();
2813 int index = 0;
2814 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2815 while (limit > 0) {
2816 index = search.Search(subject, index);
2817 if (index < 0) return;
2818 indices->Add(index);
2819 index += pattern_length;
2820 limit--;
2821 }
2822}
2823
2824
2825void FindStringIndicesDispatch(Isolate* isolate,
2826 String* subject,
2827 String* pattern,
2828 ZoneList<int>* indices,
2829 unsigned int limit) {
2830 {
2831 AssertNoAllocation no_gc;
2832 String::FlatContent subject_content = subject->GetFlatContent();
2833 String::FlatContent pattern_content = pattern->GetFlatContent();
2834 ASSERT(subject_content.IsFlat());
2835 ASSERT(pattern_content.IsFlat());
2836 if (subject_content.IsAscii()) {
2837 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2838 if (pattern_content.IsAscii()) {
2839 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2840 if (pattern_vector.length() == 1) {
2841 FindAsciiStringIndices(subject_vector,
2842 pattern_vector[0],
2843 indices,
2844 limit);
2845 } else {
2846 FindStringIndices(isolate,
2847 subject_vector,
2848 pattern_vector,
2849 indices,
2850 limit);
2851 }
2852 } else {
2853 FindStringIndices(isolate,
2854 subject_vector,
2855 pattern_content.ToUC16Vector(),
2856 indices,
2857 limit);
2858 }
2859 } else {
2860 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002861 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002862 FindStringIndices(isolate,
2863 subject_vector,
2864 pattern_content.ToAsciiVector(),
2865 indices,
2866 limit);
2867 } else {
2868 FindStringIndices(isolate,
2869 subject_vector,
2870 pattern_content.ToUC16Vector(),
2871 indices,
2872 limit);
2873 }
2874 }
2875 }
2876}
2877
2878
2879template<typename ResultSeqString>
2880MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2881 Isolate* isolate,
2882 Handle<String> subject,
2883 Handle<JSRegExp> pattern_regexp,
2884 Handle<String> replacement) {
2885 ASSERT(subject->IsFlat());
2886 ASSERT(replacement->IsFlat());
2887
2888 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2889 ZoneList<int> indices(8);
2890 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2891 String* pattern =
2892 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2893 int subject_len = subject->length();
2894 int pattern_len = pattern->length();
2895 int replacement_len = replacement->length();
2896
2897 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2898
2899 int matches = indices.length();
2900 if (matches == 0) return *subject;
2901
2902 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2903 int subject_pos = 0;
2904 int result_pos = 0;
2905
2906 Handle<ResultSeqString> result;
2907 if (ResultSeqString::kHasAsciiEncoding) {
2908 result = Handle<ResultSeqString>::cast(
2909 isolate->factory()->NewRawAsciiString(result_len));
2910 } else {
2911 result = Handle<ResultSeqString>::cast(
2912 isolate->factory()->NewRawTwoByteString(result_len));
2913 }
2914
2915 for (int i = 0; i < matches; i++) {
2916 // Copy non-matched subject content.
2917 if (subject_pos < indices.at(i)) {
2918 String::WriteToFlat(*subject,
2919 result->GetChars() + result_pos,
2920 subject_pos,
2921 indices.at(i));
2922 result_pos += indices.at(i) - subject_pos;
2923 }
2924
2925 // Replace match.
2926 if (replacement_len > 0) {
2927 String::WriteToFlat(*replacement,
2928 result->GetChars() + result_pos,
2929 0,
2930 replacement_len);
2931 result_pos += replacement_len;
2932 }
2933
2934 subject_pos = indices.at(i) + pattern_len;
2935 }
2936 // Add remaining subject content at the end.
2937 if (subject_pos < subject_len) {
2938 String::WriteToFlat(*subject,
2939 result->GetChars() + result_pos,
2940 subject_pos,
2941 subject_len);
2942 }
2943 return *result;
2944}
2945
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002946
lrn@chromium.org303ada72010-10-27 09:33:13 +00002947MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002948 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002949 String* subject,
2950 JSRegExp* regexp,
2951 String* replacement,
2952 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002953 ASSERT(subject->IsFlat());
2954 ASSERT(replacement->IsFlat());
2955
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002956 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002957
2958 int length = subject->length();
2959 Handle<String> subject_handle(subject);
2960 Handle<JSRegExp> regexp_handle(regexp);
2961 Handle<String> replacement_handle(replacement);
2962 Handle<JSArray> last_match_info_handle(last_match_info);
2963 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2964 subject_handle,
2965 0,
2966 last_match_info_handle);
2967 if (match.is_null()) {
2968 return Failure::Exception();
2969 }
2970 if (match->IsNull()) {
2971 return *subject_handle;
2972 }
2973
2974 int capture_count = regexp_handle->CaptureCount();
2975
2976 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002977 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002978 CompiledReplacement compiled_replacement;
2979 compiled_replacement.Compile(replacement_handle,
2980 capture_count,
2981 length);
2982
2983 bool is_global = regexp_handle->GetFlags().is_global();
2984
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002985 // Shortcut for simple non-regexp global replacements
2986 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002987 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002988 compiled_replacement.simple_hint()) {
2989 if (subject_handle->HasOnlyAsciiChars() &&
2990 replacement_handle->HasOnlyAsciiChars()) {
2991 return StringReplaceStringWithString<SeqAsciiString>(
2992 isolate, subject_handle, regexp_handle, replacement_handle);
2993 } else {
2994 return StringReplaceStringWithString<SeqTwoByteString>(
2995 isolate, subject_handle, regexp_handle, replacement_handle);
2996 }
2997 }
2998
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002999 // Guessing the number of parts that the final result string is built
3000 // from. Global regexps can match any number of times, so we guess
3001 // conservatively.
3002 int expected_parts =
3003 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003004 ReplacementStringBuilder builder(isolate->heap(),
3005 subject_handle,
3006 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003007
3008 // Index of end of last match.
3009 int prev = 0;
3010
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003011 // Number of parts added by compiled replacement plus preceeding
3012 // string and possibly suffix after last match. It is possible for
3013 // all components to use two elements when encoded as two smis.
3014 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003015 bool matched = true;
3016 do {
3017 ASSERT(last_match_info_handle->HasFastElements());
3018 // Increase the capacity of the builder before entering local handle-scope,
3019 // so its internal buffer can safely allocate a new handle if it grows.
3020 builder.EnsureCapacity(parts_added_per_loop);
3021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003022 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003023 int start, end;
3024 {
3025 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003026 FixedArray* match_info_array =
3027 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003028
3029 ASSERT_EQ(capture_count * 2 + 2,
3030 RegExpImpl::GetLastCaptureCount(match_info_array));
3031 start = RegExpImpl::GetCapture(match_info_array, 0);
3032 end = RegExpImpl::GetCapture(match_info_array, 1);
3033 }
3034
3035 if (prev < start) {
3036 builder.AddSubjectSlice(prev, start);
3037 }
3038 compiled_replacement.Apply(&builder,
3039 start,
3040 end,
3041 last_match_info_handle);
3042 prev = end;
3043
3044 // Only continue checking for global regexps.
3045 if (!is_global) break;
3046
3047 // Continue from where the match ended, unless it was an empty match.
3048 int next = end;
3049 if (start == end) {
3050 next = end + 1;
3051 if (next > length) break;
3052 }
3053
3054 match = RegExpImpl::Exec(regexp_handle,
3055 subject_handle,
3056 next,
3057 last_match_info_handle);
3058 if (match.is_null()) {
3059 return Failure::Exception();
3060 }
3061 matched = !match->IsNull();
3062 } while (matched);
3063
3064 if (prev < length) {
3065 builder.AddSubjectSlice(prev, length);
3066 }
3067
3068 return *(builder.ToString());
3069}
3070
3071
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003072template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003073MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003074 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003075 String* subject,
3076 JSRegExp* regexp,
3077 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078 ASSERT(subject->IsFlat());
3079
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003080 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003081
3082 Handle<String> subject_handle(subject);
3083 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003084
3085 // Shortcut for simple non-regexp global replacements
3086 if (regexp_handle->GetFlags().is_global() &&
3087 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3088 Handle<String> empty_string_handle(HEAP->empty_string());
3089 if (subject_handle->HasOnlyAsciiChars()) {
3090 return StringReplaceStringWithString<SeqAsciiString>(
3091 isolate, subject_handle, regexp_handle, empty_string_handle);
3092 } else {
3093 return StringReplaceStringWithString<SeqTwoByteString>(
3094 isolate, subject_handle, regexp_handle, empty_string_handle);
3095 }
3096 }
3097
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003098 Handle<JSArray> last_match_info_handle(last_match_info);
3099 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3100 subject_handle,
3101 0,
3102 last_match_info_handle);
3103 if (match.is_null()) return Failure::Exception();
3104 if (match->IsNull()) return *subject_handle;
3105
3106 ASSERT(last_match_info_handle->HasFastElements());
3107
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 int start, end;
3109 {
3110 AssertNoAllocation match_info_array_is_not_in_a_handle;
3111 FixedArray* match_info_array =
3112 FixedArray::cast(last_match_info_handle->elements());
3113
3114 start = RegExpImpl::GetCapture(match_info_array, 0);
3115 end = RegExpImpl::GetCapture(match_info_array, 1);
3116 }
3117
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003118 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003119 int new_length = length - (end - start);
3120 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003121 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003122 }
3123 Handle<ResultSeqString> answer;
3124 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 answer = Handle<ResultSeqString>::cast(
3126 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003127 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003128 answer = Handle<ResultSeqString>::cast(
3129 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003130 }
3131
3132 // If the regexp isn't global, only match once.
3133 if (!regexp_handle->GetFlags().is_global()) {
3134 if (start > 0) {
3135 String::WriteToFlat(*subject_handle,
3136 answer->GetChars(),
3137 0,
3138 start);
3139 }
3140 if (end < length) {
3141 String::WriteToFlat(*subject_handle,
3142 answer->GetChars() + start,
3143 end,
3144 length);
3145 }
3146 return *answer;
3147 }
3148
3149 int prev = 0; // Index of end of last match.
3150 int next = 0; // Start of next search (prev unless last match was empty).
3151 int position = 0;
3152
3153 do {
3154 if (prev < start) {
3155 // Add substring subject[prev;start] to answer string.
3156 String::WriteToFlat(*subject_handle,
3157 answer->GetChars() + position,
3158 prev,
3159 start);
3160 position += start - prev;
3161 }
3162 prev = end;
3163 next = end;
3164 // Continue from where the match ended, unless it was an empty match.
3165 if (start == end) {
3166 next++;
3167 if (next > length) break;
3168 }
3169 match = RegExpImpl::Exec(regexp_handle,
3170 subject_handle,
3171 next,
3172 last_match_info_handle);
3173 if (match.is_null()) return Failure::Exception();
3174 if (match->IsNull()) break;
3175
3176 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003177 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003178 {
3179 AssertNoAllocation match_info_array_is_not_in_a_handle;
3180 FixedArray* match_info_array =
3181 FixedArray::cast(last_match_info_handle->elements());
3182 start = RegExpImpl::GetCapture(match_info_array, 0);
3183 end = RegExpImpl::GetCapture(match_info_array, 1);
3184 }
3185 } while (true);
3186
3187 if (prev < length) {
3188 // Add substring subject[prev;length] to answer string.
3189 String::WriteToFlat(*subject_handle,
3190 answer->GetChars() + position,
3191 prev,
3192 length);
3193 position += length - prev;
3194 }
3195
3196 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003197 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003198 }
3199
3200 // Shorten string and fill
3201 int string_size = ResultSeqString::SizeFor(position);
3202 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3203 int delta = allocated_string_size - string_size;
3204
3205 answer->set_length(position);
3206 if (delta == 0) return *answer;
3207
3208 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003209 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003210 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003211 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003212 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003213
3214 return *answer;
3215}
3216
3217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003218RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003219 ASSERT(args.length() == 4);
3220
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003221 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003222 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003223 Object* flat_subject;
3224 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3225 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3226 return maybe_flat_subject;
3227 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003228 }
3229 subject = String::cast(flat_subject);
3230 }
3231
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003232 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003233 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003234 Object* flat_replacement;
3235 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3236 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3237 return maybe_flat_replacement;
3238 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003239 }
3240 replacement = String::cast(flat_replacement);
3241 }
3242
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003243 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3244 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003245
3246 ASSERT(last_match_info->HasFastElements());
3247
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003248 if (replacement->length() == 0) {
3249 if (subject->HasOnlyAsciiChars()) {
3250 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003251 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003252 } else {
3253 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003254 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003255 }
3256 }
3257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003258 return StringReplaceRegExpWithString(isolate,
3259 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003260 regexp,
3261 replacement,
3262 last_match_info);
3263}
3264
3265
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003266Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3267 Handle<String> subject,
3268 Handle<String> search,
3269 Handle<String> replace,
3270 bool* found,
3271 int recursion_limit) {
3272 if (recursion_limit == 0) return Handle<String>::null();
3273 if (subject->IsConsString()) {
3274 ConsString* cons = ConsString::cast(*subject);
3275 Handle<String> first = Handle<String>(cons->first());
3276 Handle<String> second = Handle<String>(cons->second());
3277 Handle<String> new_first =
3278 StringReplaceOneCharWithString(isolate,
3279 first,
3280 search,
3281 replace,
3282 found,
3283 recursion_limit - 1);
3284 if (*found) return isolate->factory()->NewConsString(new_first, second);
3285 if (new_first.is_null()) return new_first;
3286
3287 Handle<String> new_second =
3288 StringReplaceOneCharWithString(isolate,
3289 second,
3290 search,
3291 replace,
3292 found,
3293 recursion_limit - 1);
3294 if (*found) return isolate->factory()->NewConsString(first, new_second);
3295 if (new_second.is_null()) return new_second;
3296
3297 return subject;
3298 } else {
3299 int index = StringMatch(isolate, subject, search, 0);
3300 if (index == -1) return subject;
3301 *found = true;
3302 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3303 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3304 Handle<String> second =
3305 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3306 return isolate->factory()->NewConsString(cons1, second);
3307 }
3308}
3309
3310
3311RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3312 ASSERT(args.length() == 3);
3313 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003314 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3315 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3316 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003317
3318 // If the cons string tree is too deep, we simply abort the recursion and
3319 // retry with a flattened subject string.
3320 const int kRecursionLimit = 0x1000;
3321 bool found = false;
3322 Handle<String> result =
3323 Runtime::StringReplaceOneCharWithString(isolate,
3324 subject,
3325 search,
3326 replace,
3327 &found,
3328 kRecursionLimit);
3329 if (!result.is_null()) return *result;
3330 return *Runtime::StringReplaceOneCharWithString(isolate,
3331 FlattenGetString(subject),
3332 search,
3333 replace,
3334 &found,
3335 kRecursionLimit);
3336}
3337
3338
ager@chromium.org7c537e22008-10-16 08:43:32 +00003339// Perform string match of pattern on subject, starting at start index.
3340// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003341// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003342int Runtime::StringMatch(Isolate* isolate,
3343 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003344 Handle<String> pat,
3345 int start_index) {
3346 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003347 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003348
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003349 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003350 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003352 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003353 if (start_index + pattern_length > subject_length) return -1;
3354
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003355 if (!sub->IsFlat()) FlattenString(sub);
3356 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003357
ager@chromium.org7c537e22008-10-16 08:43:32 +00003358 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003359 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003360 String::FlatContent seq_sub = sub->GetFlatContent();
3361 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003362
ager@chromium.org7c537e22008-10-16 08:43:32 +00003363 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003364 if (seq_pat.IsAscii()) {
3365 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3366 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003367 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003368 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003369 pat_vector,
3370 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003371 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003372 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003373 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003374 pat_vector,
3375 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003376 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003377 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3378 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003380 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003381 pat_vector,
3382 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003383 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003385 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003386 pat_vector,
3387 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003388}
3389
3390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003391RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003393 ASSERT(args.length() == 3);
3394
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003395 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3396 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003397
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003398 Object* index = args[2];
3399 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003400 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003401
ager@chromium.org870a0b62008-11-04 11:43:05 +00003402 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 int position =
3404 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003405 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406}
3407
3408
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003409template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003410static int StringMatchBackwards(Vector<const schar> subject,
3411 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003412 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003413 int pattern_length = pattern.length();
3414 ASSERT(pattern_length >= 1);
3415 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003416
3417 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003418 for (int i = 0; i < pattern_length; i++) {
3419 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003420 if (c > String::kMaxAsciiCharCode) {
3421 return -1;
3422 }
3423 }
3424 }
3425
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003426 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003427 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003428 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003429 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003430 while (j < pattern_length) {
3431 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003432 break;
3433 }
3434 j++;
3435 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003436 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 return i;
3438 }
3439 }
3440 return -1;
3441}
3442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003443RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003444 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445 ASSERT(args.length() == 3);
3446
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003447 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3448 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003449
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003450 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003452 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003454 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003455 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003457 if (start_index + pat_length > sub_length) {
3458 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003459 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003461 if (pat_length == 0) {
3462 return Smi::FromInt(start_index);
3463 }
3464
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003465 if (!sub->IsFlat()) FlattenString(sub);
3466 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003467
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003468 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003469 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3470
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003471 String::FlatContent sub_content = sub->GetFlatContent();
3472 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003473
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003474 if (pat_content.IsAscii()) {
3475 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3476 if (sub_content.IsAscii()) {
3477 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003478 pat_vector,
3479 start_index);
3480 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003481 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003482 pat_vector,
3483 start_index);
3484 }
3485 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003486 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3487 if (sub_content.IsAscii()) {
3488 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003489 pat_vector,
3490 start_index);
3491 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003492 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003493 pat_vector,
3494 start_index);
3495 }
3496 }
3497
3498 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003499}
3500
3501
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003502RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003503 NoHandleAllocation ha;
3504 ASSERT(args.length() == 2);
3505
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003506 CONVERT_ARG_CHECKED(String, str1, 0);
3507 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003508
3509 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003510 int str1_length = str1->length();
3511 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512
3513 // Decide trivial cases without flattening.
3514 if (str1_length == 0) {
3515 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3516 return Smi::FromInt(-str2_length);
3517 } else {
3518 if (str2_length == 0) return Smi::FromInt(str1_length);
3519 }
3520
3521 int end = str1_length < str2_length ? str1_length : str2_length;
3522
3523 // No need to flatten if we are going to find the answer on the first
3524 // character. At this point we know there is at least one character
3525 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003526 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003527 if (d != 0) return Smi::FromInt(d);
3528
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003529 str1->TryFlatten();
3530 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 StringInputBuffer& buf1 =
3533 *isolate->runtime_state()->string_locale_compare_buf1();
3534 StringInputBuffer& buf2 =
3535 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003536
3537 buf1.Reset(str1);
3538 buf2.Reset(str2);
3539
3540 for (int i = 0; i < end; i++) {
3541 uint16_t char1 = buf1.GetNext();
3542 uint16_t char2 = buf2.GetNext();
3543 if (char1 != char2) return Smi::FromInt(char1 - char2);
3544 }
3545
3546 return Smi::FromInt(str1_length - str2_length);
3547}
3548
3549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003550RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003551 NoHandleAllocation ha;
3552 ASSERT(args.length() == 3);
3553
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003554 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003555 int start, end;
3556 // We have a fast integer-only case here to avoid a conversion to double in
3557 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003558 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3559 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3560 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3561 start = from_number;
3562 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003563 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003564 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3565 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003566 start = FastD2I(from_number);
3567 end = FastD2I(to_number);
3568 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569 RUNTIME_ASSERT(end >= start);
3570 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003571 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003573 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003574}
3575
3576
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003577RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003578 ASSERT_EQ(3, args.length());
3579
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003580 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3581 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3582 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003583 HandleScope handles;
3584
3585 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3586
3587 if (match.is_null()) {
3588 return Failure::Exception();
3589 }
3590 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003592 }
3593 int length = subject->length();
3594
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003595 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003596 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003597 int start;
3598 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003599 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003600 {
3601 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003602 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003603 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3604 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3605 }
3606 offsets.Add(start);
3607 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003608 if (start == end) if (++end > length) break;
3609 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003610 if (match.is_null()) {
3611 return Failure::Exception();
3612 }
3613 } while (!match->IsNull());
3614 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003616 Handle<String> substring = isolate->factory()->
3617 NewSubString(subject, offsets.at(0), offsets.at(1));
3618 elements->set(0, *substring);
3619 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 int from = offsets.at(i * 2);
3621 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003622 Handle<String> substring = isolate->factory()->
3623 NewProperSubString(subject, from, to);
3624 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003625 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003626 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003627 result->set_length(Smi::FromInt(matches));
3628 return *result;
3629}
3630
3631
lrn@chromium.org25156de2010-04-06 13:10:27 +00003632// Two smis before and after the match, for very long strings.
3633const int kMaxBuilderEntriesPerRegExpMatch = 5;
3634
3635
3636static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3637 Handle<JSArray> last_match_info,
3638 int match_start,
3639 int match_end) {
3640 // Fill last_match_info with a single capture.
3641 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3642 AssertNoAllocation no_gc;
3643 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3644 RegExpImpl::SetLastCaptureCount(elements, 2);
3645 RegExpImpl::SetLastInput(elements, *subject);
3646 RegExpImpl::SetLastSubject(elements, *subject);
3647 RegExpImpl::SetCapture(elements, 0, match_start);
3648 RegExpImpl::SetCapture(elements, 1, match_end);
3649}
3650
3651
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003652template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653static bool SearchStringMultiple(Isolate* isolate,
3654 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003655 Vector<const PatternChar> pattern,
3656 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003657 FixedArrayBuilder* builder,
3658 int* match_pos) {
3659 int pos = *match_pos;
3660 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003661 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003662 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003664 while (pos <= max_search_start) {
3665 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3666 *match_pos = pos;
3667 return false;
3668 }
3669 // Position of end of previous match.
3670 int match_end = pos + pattern_length;
3671 int new_pos = search.Search(subject, match_end);
3672 if (new_pos >= 0) {
3673 // A match.
3674 if (new_pos > match_end) {
3675 ReplacementStringBuilder::AddSubjectSlice(builder,
3676 match_end,
3677 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003679 pos = new_pos;
3680 builder->Add(pattern_string);
3681 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003682 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003683 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003684 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003685
lrn@chromium.org25156de2010-04-06 13:10:27 +00003686 if (pos < max_search_start) {
3687 ReplacementStringBuilder::AddSubjectSlice(builder,
3688 pos + pattern_length,
3689 subject_length);
3690 }
3691 *match_pos = pos;
3692 return true;
3693}
3694
3695
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696static bool SearchStringMultiple(Isolate* isolate,
3697 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003698 Handle<String> pattern,
3699 Handle<JSArray> last_match_info,
3700 FixedArrayBuilder* builder) {
3701 ASSERT(subject->IsFlat());
3702 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003703
3704 // Treating as if a previous match was before first character.
3705 int match_pos = -pattern->length();
3706
3707 for (;;) { // Break when search complete.
3708 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3709 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003710 String::FlatContent subject_content = subject->GetFlatContent();
3711 String::FlatContent pattern_content = pattern->GetFlatContent();
3712 if (subject_content.IsAscii()) {
3713 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3714 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003715 if (SearchStringMultiple(isolate,
3716 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003717 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003718 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 builder,
3720 &match_pos)) break;
3721 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003722 if (SearchStringMultiple(isolate,
3723 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003724 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003725 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003726 builder,
3727 &match_pos)) break;
3728 }
3729 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003730 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3731 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 if (SearchStringMultiple(isolate,
3733 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003734 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003735 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003736 builder,
3737 &match_pos)) break;
3738 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 if (SearchStringMultiple(isolate,
3740 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003741 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003742 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003743 builder,
3744 &match_pos)) break;
3745 }
3746 }
3747 }
3748
3749 if (match_pos >= 0) {
3750 SetLastMatchInfoNoCaptures(subject,
3751 last_match_info,
3752 match_pos,
3753 match_pos + pattern->length());
3754 return true;
3755 }
3756 return false; // No matches at all.
3757}
3758
3759
3760static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003762 Handle<String> subject,
3763 Handle<JSRegExp> regexp,
3764 Handle<JSArray> last_match_array,
3765 FixedArrayBuilder* builder) {
3766 ASSERT(subject->IsFlat());
3767 int match_start = -1;
3768 int match_end = 0;
3769 int pos = 0;
3770 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3771 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3772
ulan@chromium.org812308e2012-02-29 15:58:45 +00003773 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003774 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003775 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003776 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003777
3778 for (;;) { // Break on failure, return on exception.
3779 RegExpImpl::IrregexpResult result =
3780 RegExpImpl::IrregexpExecOnce(regexp,
3781 subject,
3782 pos,
3783 register_vector);
3784 if (result == RegExpImpl::RE_SUCCESS) {
3785 match_start = register_vector[0];
3786 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3787 if (match_end < match_start) {
3788 ReplacementStringBuilder::AddSubjectSlice(builder,
3789 match_end,
3790 match_start);
3791 }
3792 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003794 if (!first) {
3795 builder->Add(*isolate->factory()->NewProperSubString(subject,
3796 match_start,
3797 match_end));
3798 } else {
3799 builder->Add(*isolate->factory()->NewSubString(subject,
3800 match_start,
3801 match_end));
3802 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003803 if (match_start != match_end) {
3804 pos = match_end;
3805 } else {
3806 pos = match_end + 1;
3807 if (pos > subject_length) break;
3808 }
3809 } else if (result == RegExpImpl::RE_FAILURE) {
3810 break;
3811 } else {
3812 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3813 return result;
3814 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003815 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003816 }
3817
3818 if (match_start >= 0) {
3819 if (match_end < subject_length) {
3820 ReplacementStringBuilder::AddSubjectSlice(builder,
3821 match_end,
3822 subject_length);
3823 }
3824 SetLastMatchInfoNoCaptures(subject,
3825 last_match_array,
3826 match_start,
3827 match_end);
3828 return RegExpImpl::RE_SUCCESS;
3829 } else {
3830 return RegExpImpl::RE_FAILURE; // No matches at all.
3831 }
3832}
3833
3834
3835static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003836 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003837 Handle<String> subject,
3838 Handle<JSRegExp> regexp,
3839 Handle<JSArray> last_match_array,
3840 FixedArrayBuilder* builder) {
3841
3842 ASSERT(subject->IsFlat());
3843 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3844 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3845
ulan@chromium.org812308e2012-02-29 15:58:45 +00003846 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003847 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003848
3849 RegExpImpl::IrregexpResult result =
3850 RegExpImpl::IrregexpExecOnce(regexp,
3851 subject,
3852 0,
3853 register_vector);
3854
3855 int capture_count = regexp->CaptureCount();
3856 int subject_length = subject->length();
3857
3858 // Position to search from.
3859 int pos = 0;
3860 // End of previous match. Differs from pos if match was empty.
3861 int match_end = 0;
3862 if (result == RegExpImpl::RE_SUCCESS) {
3863 // Need to keep a copy of the previous match for creating last_match_info
3864 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003865 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003866 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003867 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003868 do {
3869 int match_start = register_vector[0];
3870 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3871 if (match_end < match_start) {
3872 ReplacementStringBuilder::AddSubjectSlice(builder,
3873 match_end,
3874 match_start);
3875 }
3876 match_end = register_vector[1];
3877
3878 {
3879 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003880 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003881 // Arguments array to replace function is match, captures, index and
3882 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003883 Handle<FixedArray> elements =
3884 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003885 Handle<String> match;
3886 if (!first) {
3887 match = isolate->factory()->NewProperSubString(subject,
3888 match_start,
3889 match_end);
3890 } else {
3891 match = isolate->factory()->NewSubString(subject,
3892 match_start,
3893 match_end);
3894 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003895 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003896 for (int i = 1; i <= capture_count; i++) {
3897 int start = register_vector[i * 2];
3898 if (start >= 0) {
3899 int end = register_vector[i * 2 + 1];
3900 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003901 Handle<String> substring;
3902 if (!first) {
3903 substring = isolate->factory()->NewProperSubString(subject,
3904 start,
3905 end);
3906 } else {
3907 substring = isolate->factory()->NewSubString(subject, start, end);
3908 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003909 elements->set(i, *substring);
3910 } else {
3911 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003912 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003913 }
3914 }
3915 elements->set(capture_count + 1, Smi::FromInt(match_start));
3916 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003918 }
3919 // Swap register vectors, so the last successful match is in
3920 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003921 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003922 prev_register_vector = register_vector;
3923 register_vector = tmp;
3924
3925 if (match_end > match_start) {
3926 pos = match_end;
3927 } else {
3928 pos = match_end + 1;
3929 if (pos > subject_length) {
3930 break;
3931 }
3932 }
3933
3934 result = RegExpImpl::IrregexpExecOnce(regexp,
3935 subject,
3936 pos,
3937 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003938 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003939 } while (result == RegExpImpl::RE_SUCCESS);
3940
3941 if (result != RegExpImpl::RE_EXCEPTION) {
3942 // Finished matching, with at least one match.
3943 if (match_end < subject_length) {
3944 ReplacementStringBuilder::AddSubjectSlice(builder,
3945 match_end,
3946 subject_length);
3947 }
3948
3949 int last_match_capture_count = (capture_count + 1) * 2;
3950 int last_match_array_size =
3951 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3952 last_match_array->EnsureSize(last_match_array_size);
3953 AssertNoAllocation no_gc;
3954 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3955 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3956 RegExpImpl::SetLastSubject(elements, *subject);
3957 RegExpImpl::SetLastInput(elements, *subject);
3958 for (int i = 0; i < last_match_capture_count; i++) {
3959 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3960 }
3961 return RegExpImpl::RE_SUCCESS;
3962 }
3963 }
3964 // No matches at all, return failure or exception result directly.
3965 return result;
3966}
3967
3968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003969RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003970 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003971 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003972
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003973 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003974 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003975 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3976 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3977 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003978
3979 ASSERT(last_match_info->HasFastElements());
3980 ASSERT(regexp->GetFlags().is_global());
3981 Handle<FixedArray> result_elements;
3982 if (result_array->HasFastElements()) {
3983 result_elements =
3984 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003985 }
3986 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003987 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003988 }
3989 FixedArrayBuilder builder(result_elements);
3990
3991 if (regexp->TypeTag() == JSRegExp::ATOM) {
3992 Handle<String> pattern(
3993 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003994 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003995 if (SearchStringMultiple(isolate, subject, pattern,
3996 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003997 return *builder.ToJSArray(result_array);
3998 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004000 }
4001
4002 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4003
4004 RegExpImpl::IrregexpResult result;
4005 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 result = SearchRegExpNoCaptureMultiple(isolate,
4007 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004008 regexp,
4009 last_match_info,
4010 &builder);
4011 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004012 result = SearchRegExpMultiple(isolate,
4013 subject,
4014 regexp,
4015 last_match_info,
4016 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004017 }
4018 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004019 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004020 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4021 return Failure::Exception();
4022}
4023
4024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004025RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 NoHandleAllocation ha;
4027 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004028 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004029 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004031 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004032 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004033 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004034 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004035 // Character array used for conversion.
4036 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004037 return isolate->heap()->
4038 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004039 }
4040 }
4041
4042 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004043 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004044 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004045 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 }
4047 if (isinf(value)) {
4048 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004049 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004051 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004054 MaybeObject* result =
4055 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 DeleteArray(str);
4057 return result;
4058}
4059
4060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004061RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 NoHandleAllocation ha;
4063 ASSERT(args.length() == 2);
4064
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004065 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004067 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068 }
4069 if (isinf(value)) {
4070 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004071 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004073 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004075 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 int f = FastD2I(f_number);
4077 RUNTIME_ASSERT(f >= 0);
4078 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004079 MaybeObject* res =
4080 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004082 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083}
4084
4085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004086RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 NoHandleAllocation ha;
4088 ASSERT(args.length() == 2);
4089
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004090 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004092 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 }
4094 if (isinf(value)) {
4095 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004096 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004098 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004100 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 int f = FastD2I(f_number);
4102 RUNTIME_ASSERT(f >= -1 && f <= 20);
4103 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004104 MaybeObject* res =
4105 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004107 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108}
4109
4110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
4113 ASSERT(args.length() == 2);
4114
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004115 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004117 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 }
4119 if (isinf(value)) {
4120 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004121 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004123 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004125 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 int f = FastD2I(f_number);
4127 RUNTIME_ASSERT(f >= 1 && f <= 21);
4128 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004129 MaybeObject* res =
4130 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004132 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133}
4134
4135
4136// Returns a single character string where first character equals
4137// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004138static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004139 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004140 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004141 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004142 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004144 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145}
4146
4147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4149 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004150 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 // Handle [] indexing on Strings
4152 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004153 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4154 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 }
4156
4157 // Handle [] indexing on String objects
4158 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004159 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4160 Handle<Object> result =
4161 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4162 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163 }
4164
4165 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004166 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 }
4168
4169 return object->GetElement(index);
4170}
4171
4172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4174 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004175 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004177
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004179 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004181 isolate->factory()->NewTypeError("non_object_property_load",
4182 HandleVector(args, 2));
4183 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004184 }
4185
4186 // Check if the given key is an array index.
4187 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004188 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 }
4191
4192 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004193 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004195 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004196 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 bool has_pending_exception = false;
4198 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004199 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004201 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
4203
ager@chromium.org32912102009-01-16 10:38:43 +00004204 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 // the element if so.
4206 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004207 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004209 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 }
4211}
4212
4213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004214RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215 NoHandleAllocation ha;
4216 ASSERT(args.length() == 2);
4217
4218 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004219 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004221 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222}
4223
4224
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004225// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004226RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004227 NoHandleAllocation ha;
4228 ASSERT(args.length() == 2);
4229
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004230 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004231 // itself.
4232 //
4233 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004234 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004235 // global proxy object never has properties. This is the case
4236 // because the global proxy object forwards everything to its hidden
4237 // prototype including local lookups.
4238 //
4239 // Additionally, we need to make sure that we do not cache results
4240 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004241 if (args[0]->IsJSObject()) {
4242 if (!args[0]->IsJSGlobalProxy() &&
4243 !args[0]->IsAccessCheckNeeded() &&
4244 args[1]->IsString()) {
4245 JSObject* receiver = JSObject::cast(args[0]);
4246 String* key = String::cast(args[1]);
4247 if (receiver->HasFastProperties()) {
4248 // Attempt to use lookup cache.
4249 Map* receiver_map = receiver->map();
4250 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4251 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4252 if (offset != -1) {
4253 Object* value = receiver->FastPropertyAt(offset);
4254 return value->IsTheHole()
4255 ? isolate->heap()->undefined_value()
4256 : value;
4257 }
4258 // Lookup cache miss. Perform lookup and update the cache if
4259 // appropriate.
4260 LookupResult result(isolate);
4261 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004262 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004263 int offset = result.GetFieldIndex();
4264 keyed_lookup_cache->Update(receiver_map, key, offset);
4265 return receiver->FastPropertyAt(offset);
4266 }
4267 } else {
4268 // Attempt dictionary lookup.
4269 StringDictionary* dictionary = receiver->property_dictionary();
4270 int entry = dictionary->FindEntry(key);
4271 if ((entry != StringDictionary::kNotFound) &&
4272 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4273 Object* value = dictionary->ValueAt(entry);
4274 if (!receiver->IsGlobalObject()) return value;
4275 value = JSGlobalPropertyCell::cast(value)->value();
4276 if (!value->IsTheHole()) return value;
4277 // If value is the hole do the general lookup.
4278 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004279 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004280 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4281 // JSObject without a string key. If the key is a Smi, check for a
4282 // definite out-of-bounds access to elements, which is a strong indicator
4283 // that subsequent accesses will also call the runtime. Proactively
4284 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4285 // doubles for those future calls in the case that the elements would
4286 // become FAST_DOUBLE_ELEMENTS.
4287 Handle<JSObject> js_object(args.at<JSObject>(0));
4288 ElementsKind elements_kind = js_object->GetElementsKind();
4289 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4290 elements_kind == FAST_DOUBLE_ELEMENTS) {
4291 FixedArrayBase* elements = js_object->elements();
4292 if (args.at<Smi>(1)->value() >= elements->length()) {
4293 MaybeObject* maybe_object = TransitionElements(js_object,
4294 FAST_ELEMENTS,
4295 isolate);
4296 if (maybe_object->IsFailure()) return maybe_object;
4297 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004298 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004299 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004300 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4301 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004303 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004304 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004305 if (index >= 0 && index < str->length()) {
4306 Handle<Object> result = GetCharAt(str, index);
4307 return *result;
4308 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004309 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004310
4311 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 return Runtime::GetObjectProperty(isolate,
4313 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004314 args.at<Object>(1));
4315}
4316
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004317
4318static bool IsValidAccessor(Handle<Object> obj) {
4319 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4320}
4321
4322
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004323// Implements part of 8.12.9 DefineOwnProperty.
4324// There are 3 cases that lead here:
4325// Step 4b - define a new accessor property.
4326// Steps 9c & 12 - replace an existing data property with an accessor property.
4327// Step 12 - update an existing accessor property with an accessor or generic
4328// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004329RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004330 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004331 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004332 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004333 RUNTIME_ASSERT(!obj->IsNull());
4334 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4335 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4336 RUNTIME_ASSERT(IsValidAccessor(getter));
4337 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4338 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004339 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004340 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004341 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004342
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004343 // TODO(svenpanne) Define getter/setter/attributes in a single step.
4344 if (getter->IsNull() && setter->IsNull()) {
4345 JSArray* array;
4346 { MaybeObject* maybe_array = GetOwnProperty(isolate, obj, name);
4347 if (!maybe_array->To(&array)) return maybe_array;
4348 }
4349 Object* current = FixedArray::cast(array->elements())->get(GETTER_INDEX);
4350 getter = Handle<Object>(current, isolate);
4351 }
4352 if (!getter->IsNull()) {
4353 MaybeObject* ok =
4354 obj->DefineAccessor(*name, ACCESSOR_GETTER, *getter, attr);
4355 if (ok->IsFailure()) return ok;
4356 }
4357 if (!setter->IsNull()) {
4358 MaybeObject* ok =
4359 obj->DefineAccessor(*name, ACCESSOR_SETTER, *setter, attr);
4360 if (ok->IsFailure()) return ok;
4361 }
4362
4363 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004364}
4365
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004366// Implements part of 8.12.9 DefineOwnProperty.
4367// There are 3 cases that lead here:
4368// Step 4a - define a new data property.
4369// Steps 9b & 12 - replace an existing accessor property with a data property.
4370// Step 12 - update an existing data property with a data or generic
4371// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004372RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004373 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004374 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004375 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4376 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004377 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004378 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004379 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004380 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4381
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004382 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004383 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004384
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004385 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004386 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004387 Object* callback = result.GetCallbackObject();
4388 // To be compatible with Safari we do not change the value on API objects
4389 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4390 // the value.
4391 if (callback->IsAccessorInfo()) {
4392 return isolate->heap()->undefined_value();
4393 }
4394 // Avoid redefining foreign callback as data property, just use the stored
4395 // setter to update the value instead.
4396 // TODO(mstarzinger): So far this only works if property attributes don't
4397 // change, this should be fixed once we cleanup the underlying code.
4398 if (callback->IsForeign() && result.GetAttributes() == attr) {
4399 return js_object->SetPropertyWithCallback(callback,
4400 *name,
4401 *obj_value,
4402 result.holder(),
4403 kStrictMode);
4404 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004405 }
4406
ager@chromium.org5c838252010-02-19 08:53:10 +00004407 // Take special care when attributes are different and there is already
4408 // a property. For simplicity we normalize the property which enables us
4409 // to not worry about changing the instance_descriptor and creating a new
4410 // map. The current version of SetObjectProperty does not handle attributes
4411 // correctly in the case where a property is a field and is reset with
4412 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004413 if (result.IsProperty() &&
4414 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004415 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004416 if (js_object->IsJSGlobalProxy()) {
4417 // Since the result is a property, the prototype will exist so
4418 // we don't have to check for null.
4419 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004420 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004421 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004422 // Use IgnoreAttributes version since a readonly property may be
4423 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004424 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4425 *obj_value,
4426 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004427 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004429 return Runtime::ForceSetObjectProperty(isolate,
4430 js_object,
4431 name,
4432 obj_value,
4433 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004434}
4435
4436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004437MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4438 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004439 Handle<Object> key,
4440 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004441 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004442 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004443 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004444 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004447 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 isolate->factory()->NewTypeError("non_object_property_store",
4450 HandleVector(args, 2));
4451 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004452 }
4453
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004454 if (object->IsJSProxy()) {
4455 bool has_pending_exception = false;
4456 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4457 if (has_pending_exception) return Failure::Exception();
4458 return JSProxy::cast(*object)->SetProperty(
4459 String::cast(*name), *value, attr, strict_mode);
4460 }
4461
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004462 // If the object isn't a JavaScript object, we ignore the store.
4463 if (!object->IsJSObject()) return *value;
4464
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004465 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 // Check if the given key is an array index.
4468 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004469 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4471 // of a string using [] notation. We need to support this too in
4472 // JavaScript.
4473 // In the case of a String object we just need to redirect the assignment to
4474 // the underlying string if the index is in range. Since the underlying
4475 // string does nothing with the assignment then we can ignore such
4476 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004477 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004479 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004481 Handle<Object> result = JSObject::SetElement(
4482 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004483 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 return *value;
4485 }
4486
4487 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004488 Handle<Object> result;
4489 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004490 result = JSObject::SetElement(
4491 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004493 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004494 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004495 result = JSReceiver::SetProperty(
4496 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004498 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 return *value;
4500 }
4501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 bool has_pending_exception = false;
4504 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4505 if (has_pending_exception) return Failure::Exception();
4506 Handle<String> name = Handle<String>::cast(converted);
4507
4508 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004509 return js_object->SetElement(
4510 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004512 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 }
4514}
4515
4516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004517MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4518 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004519 Handle<Object> key,
4520 Handle<Object> value,
4521 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004522 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004523
4524 // Check if the given key is an array index.
4525 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004526 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004527 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4528 // of a string using [] notation. We need to support this too in
4529 // JavaScript.
4530 // In the case of a String object we just need to redirect the assignment to
4531 // the underlying string if the index is in range. Since the underlying
4532 // string does nothing with the assignment then we can ignore such
4533 // assignments.
4534 if (js_object->IsStringObjectWithCharacterAt(index)) {
4535 return *value;
4536 }
4537
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004538 return js_object->SetElement(
4539 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004540 }
4541
4542 if (key->IsString()) {
4543 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004544 return js_object->SetElement(
4545 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004546 } else {
4547 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004548 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004549 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4550 *value,
4551 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004552 }
4553 }
4554
4555 // Call-back into JavaScript to convert the key to a string.
4556 bool has_pending_exception = false;
4557 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4558 if (has_pending_exception) return Failure::Exception();
4559 Handle<String> name = Handle<String>::cast(converted);
4560
4561 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004562 return js_object->SetElement(
4563 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004564 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004565 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004566 }
4567}
4568
4569
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004570MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004571 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004572 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004573 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004574
4575 // Check if the given key is an array index.
4576 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004577 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004578 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4579 // characters of a string using [] notation. In the case of a
4580 // String object we just need to redirect the deletion to the
4581 // underlying string if the index is in range. Since the
4582 // underlying string does nothing with the deletion, we can ignore
4583 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004584 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004585 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004586 }
4587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004588 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004589 }
4590
4591 Handle<String> key_string;
4592 if (key->IsString()) {
4593 key_string = Handle<String>::cast(key);
4594 } else {
4595 // Call-back into JavaScript to convert the key to a string.
4596 bool has_pending_exception = false;
4597 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4598 if (has_pending_exception) return Failure::Exception();
4599 key_string = Handle<String>::cast(converted);
4600 }
4601
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004602 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004603 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004604}
4605
4606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004607RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004609 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610
4611 Handle<Object> object = args.at<Object>(0);
4612 Handle<Object> key = args.at<Object>(1);
4613 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004614 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004615 RUNTIME_ASSERT(
4616 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004617 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004618 PropertyAttributes attributes =
4619 static_cast<PropertyAttributes>(unchecked_attributes);
4620
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004621 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004622 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004623 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004624 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004626
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 return Runtime::SetObjectProperty(isolate,
4628 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004629 key,
4630 value,
4631 attributes,
4632 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633}
4634
4635
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004636RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4637 NoHandleAllocation ha;
4638 RUNTIME_ASSERT(args.length() == 1);
4639 Handle<Object> object = args.at<Object>(0);
4640 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4641}
4642
4643
4644RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4645 NoHandleAllocation ha;
4646 RUNTIME_ASSERT(args.length() == 1);
4647 Handle<Object> object = args.at<Object>(0);
4648 return TransitionElements(object, FAST_ELEMENTS, isolate);
4649}
4650
4651
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004652// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004653// This is used to decide if we should transform null and undefined
4654// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004656 NoHandleAllocation ha;
4657 RUNTIME_ASSERT(args.length() == 1);
4658
4659 Handle<Object> object = args.at<Object>(0);
4660
4661 if (object->IsJSFunction()) {
4662 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004663 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004664 }
4665 return isolate->heap()->undefined_value();
4666}
4667
4668
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004669RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4670 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004671 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004672 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4673 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004674 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004675 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4676 HandleScope scope;
4677
4678 Object* raw_boilerplate_object = literals->get(literal_index);
4679 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4680#if DEBUG
4681 ElementsKind elements_kind = object->GetElementsKind();
4682#endif
4683 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4684 // Smis should never trigger transitions.
4685 ASSERT(!value->IsSmi());
4686
4687 if (value->IsNumber()) {
4688 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004689 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4690 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004691 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4692 FixedDoubleArray* double_array =
4693 FixedDoubleArray::cast(object->elements());
4694 HeapNumber* number = HeapNumber::cast(*value);
4695 double_array->set(store_index, number->Number());
4696 } else {
4697 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4698 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004699 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4700 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004701 FixedArray* object_array =
4702 FixedArray::cast(object->elements());
4703 object_array->set(store_index, *value);
4704 }
4705 return *object;
4706}
4707
4708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709// Set a local property, even if it is READ_ONLY. If the property does not
4710// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004711RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004713 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004714 CONVERT_ARG_CHECKED(JSObject, object, 0);
4715 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004716 // Compute attributes.
4717 PropertyAttributes attributes = NONE;
4718 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004719 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004720 // Only attribute bits should be set.
4721 RUNTIME_ASSERT(
4722 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4723 attributes = static_cast<PropertyAttributes>(unchecked_value);
4724 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004726 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004727 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004728}
4729
4730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004731RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004733 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004735 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4736 CONVERT_ARG_CHECKED(String, key, 1);
4737 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004738 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004739 ? JSReceiver::STRICT_DELETION
4740 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004741}
4742
4743
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004744static Object* HasLocalPropertyImplementation(Isolate* isolate,
4745 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004746 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004748 // Handle hidden prototypes. If there's a hidden prototype above this thing
4749 // then we have to check it for properties, because they are supposed to
4750 // look like they are on this object.
4751 Handle<Object> proto(object->GetPrototype());
4752 if (proto->IsJSObject() &&
4753 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004754 return HasLocalPropertyImplementation(isolate,
4755 Handle<JSObject>::cast(proto),
4756 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004757 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004758 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004759}
4760
4761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004762RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 NoHandleAllocation ha;
4764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004765 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004767 uint32_t index;
4768 const bool key_is_array_index = key->AsArrayIndex(&index);
4769
ager@chromium.org9085a012009-05-11 19:22:57 +00004770 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004772 if (obj->IsJSObject()) {
4773 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004774 // Fast case: either the key is a real named property or it is not
4775 // an array index and there are no interceptors or hidden
4776 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004777 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004778 Map* map = object->map();
4779 if (!key_is_array_index &&
4780 !map->has_named_interceptor() &&
4781 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4782 return isolate->heap()->false_value();
4783 }
4784 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004785 HandleScope scope(isolate);
4786 return HasLocalPropertyImplementation(isolate,
4787 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004788 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004789 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004791 String* string = String::cast(obj);
4792 if (index < static_cast<uint32_t>(string->length())) {
4793 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 }
4795 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797}
4798
4799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004800RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 NoHandleAllocation na;
4802 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004803 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4804 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004806 bool result = receiver->HasProperty(key);
4807 if (isolate->has_pending_exception()) return Failure::Exception();
4808 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004809}
4810
4811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004812RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 NoHandleAllocation na;
4814 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004815 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4816 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004818 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004819 if (isolate->has_pending_exception()) return Failure::Exception();
4820 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004821}
4822
4823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004824RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 NoHandleAllocation ha;
4826 ASSERT(args.length() == 2);
4827
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004828 CONVERT_ARG_CHECKED(JSObject, object, 0);
4829 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830
4831 uint32_t index;
4832 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004833 JSObject::LocalElementType type = object->HasLocalElement(index);
4834 switch (type) {
4835 case JSObject::UNDEFINED_ELEMENT:
4836 case JSObject::STRING_CHARACTER_ELEMENT:
4837 return isolate->heap()->false_value();
4838 case JSObject::INTERCEPTED_ELEMENT:
4839 case JSObject::FAST_ELEMENT:
4840 return isolate->heap()->true_value();
4841 case JSObject::DICTIONARY_ELEMENT: {
4842 if (object->IsJSGlobalProxy()) {
4843 Object* proto = object->GetPrototype();
4844 if (proto->IsNull()) {
4845 return isolate->heap()->false_value();
4846 }
4847 ASSERT(proto->IsJSGlobalObject());
4848 object = JSObject::cast(proto);
4849 }
4850 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004851 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004852 if (elements->map() ==
4853 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004854 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004855 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004856 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004857 }
4858 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004859 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004860 PropertyDetails details = dictionary->DetailsAt(entry);
4861 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4862 }
4863 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 }
4865
ager@chromium.org870a0b62008-11-04 11:43:05 +00004866 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004867 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868}
4869
4870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004872 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004874 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004875 bool threw = false;
4876 Handle<JSArray> result = GetKeysFor(object, &threw);
4877 if (threw) return Failure::Exception();
4878 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879}
4880
4881
4882// Returns either a FixedArray as Runtime_GetPropertyNames,
4883// or, if the given object has an enum cache that contains
4884// all enumerable properties of the object and its prototypes
4885// have none, the map of the object. This is used to speed up
4886// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004887RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 ASSERT(args.length() == 1);
4889
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004890 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891
4892 if (raw_object->IsSimpleEnum()) return raw_object->map();
4893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004895 Handle<JSReceiver> object(raw_object);
4896 bool threw = false;
4897 Handle<FixedArray> content =
4898 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4899 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900
4901 // Test again, since cache may have been built by preceding call.
4902 if (object->IsSimpleEnum()) return object->map();
4903
4904 return *content;
4905}
4906
4907
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004908// Find the length of the prototype chain that is to to handled as one. If a
4909// prototype object is hidden it is to be viewed as part of the the object it
4910// is prototype for.
4911static int LocalPrototypeChainLength(JSObject* obj) {
4912 int count = 1;
4913 Object* proto = obj->GetPrototype();
4914 while (proto->IsJSObject() &&
4915 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4916 count++;
4917 proto = JSObject::cast(proto)->GetPrototype();
4918 }
4919 return count;
4920}
4921
4922
4923// Return the names of the local named properties.
4924// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004925RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004926 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004927 ASSERT(args.length() == 1);
4928 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004929 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004930 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004931 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004932
4933 // Skip the global proxy as it has no properties and always delegates to the
4934 // real global object.
4935 if (obj->IsJSGlobalProxy()) {
4936 // Only collect names if access is permitted.
4937 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004938 !isolate->MayNamedAccess(*obj,
4939 isolate->heap()->undefined_value(),
4940 v8::ACCESS_KEYS)) {
4941 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4942 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004943 }
4944 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4945 }
4946
4947 // Find the number of objects making up this.
4948 int length = LocalPrototypeChainLength(*obj);
4949
4950 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004951 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004952 int total_property_count = 0;
4953 Handle<JSObject> jsproto = obj;
4954 for (int i = 0; i < length; i++) {
4955 // Only collect names if access is permitted.
4956 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004957 !isolate->MayNamedAccess(*jsproto,
4958 isolate->heap()->undefined_value(),
4959 v8::ACCESS_KEYS)) {
4960 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4961 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004962 }
4963 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004964 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004965 local_property_count[i] = n;
4966 total_property_count += n;
4967 if (i < length - 1) {
4968 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4969 }
4970 }
4971
4972 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004973 Handle<FixedArray> names =
4974 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004975
4976 // Get the property names.
4977 jsproto = obj;
4978 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004979 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004980 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004981 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4982 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004983 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984 proto_with_hidden_properties++;
4985 }
4986 if (i < length - 1) {
4987 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4988 }
4989 }
4990
4991 // Filter out name of hidden propeties object.
4992 if (proto_with_hidden_properties > 0) {
4993 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004994 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004995 names->length() - proto_with_hidden_properties);
4996 int dest_pos = 0;
4997 for (int i = 0; i < total_property_count; i++) {
4998 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005000 continue;
5001 }
5002 names->set(dest_pos++, name);
5003 }
5004 }
5005
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005007}
5008
5009
5010// Return the names of the local indexed properties.
5011// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005012RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005013 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005014 ASSERT(args.length() == 1);
5015 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005018 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005019
5020 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005022 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005023 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005024}
5025
5026
5027// Return information on whether an object has a named or indexed interceptor.
5028// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005029RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005030 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005031 ASSERT(args.length() == 1);
5032 if (!args[0]->IsJSObject()) {
5033 return Smi::FromInt(0);
5034 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005035 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005036
5037 int result = 0;
5038 if (obj->HasNamedInterceptor()) result |= 2;
5039 if (obj->HasIndexedInterceptor()) result |= 1;
5040
5041 return Smi::FromInt(result);
5042}
5043
5044
5045// Return property names from named interceptor.
5046// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005047RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005048 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005049 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005050 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005051
5052 if (obj->HasNamedInterceptor()) {
5053 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5054 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5055 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005056 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005057}
5058
5059
5060// Return element names from indexed interceptor.
5061// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005062RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005064 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005065 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005066
5067 if (obj->HasIndexedInterceptor()) {
5068 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5069 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5070 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005072}
5073
5074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005075RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005076 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005077 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005079 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005080
5081 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005082 // Do access checks before going to the global object.
5083 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005085 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005086 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5087 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005088 }
5089
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005090 Handle<Object> proto(object->GetPrototype());
5091 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005092 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005093 object = Handle<JSObject>::cast(proto);
5094 }
5095
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005096 bool threw = false;
5097 Handle<FixedArray> contents =
5098 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5099 if (threw) return Failure::Exception();
5100
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005101 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5102 // property array and since the result is mutable we have to create
5103 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005104 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005105 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005106 for (int i = 0; i < length; i++) {
5107 Object* entry = contents->get(i);
5108 if (entry->IsString()) {
5109 copy->set(i, entry);
5110 } else {
5111 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 HandleScope scope(isolate);
5113 Handle<Object> entry_handle(entry, isolate);
5114 Handle<Object> entry_str =
5115 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005116 copy->set(i, *entry_str);
5117 }
5118 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005119 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005120}
5121
5122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005123RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124 NoHandleAllocation ha;
5125 ASSERT(args.length() == 1);
5126
5127 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005128 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005129 it.AdvanceToArgumentsFrame();
5130 JavaScriptFrame* frame = it.frame();
5131
5132 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005133 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005134
5135 // Try to convert the key to an index. If successful and within
5136 // index return the the argument from the frame.
5137 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005138 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005139 return frame->GetParameter(index);
5140 }
5141
5142 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005143 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005144 bool exception = false;
5145 Handle<Object> converted =
5146 Execution::ToString(args.at<Object>(0), &exception);
5147 if (exception) return Failure::Exception();
5148 Handle<String> key = Handle<String>::cast(converted);
5149
5150 // Try to convert the string key into an array index.
5151 if (key->AsArrayIndex(&index)) {
5152 if (index < n) {
5153 return frame->GetParameter(index);
5154 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005155 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156 }
5157 }
5158
5159 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005160 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5161 if (key->Equals(isolate->heap()->callee_symbol())) {
5162 Object* function = frame->function();
5163 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005164 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return isolate->Throw(*isolate->factory()->NewTypeError(
5166 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5167 }
5168 return function;
5169 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005170
5171 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173}
5174
5175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005176RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005177 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005178 Object* object = args[0];
5179 return (object->IsJSObject() && !object->IsGlobalObject())
5180 ? JSObject::cast(object)->TransformToFastProperties(0)
5181 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005182}
5183
5184
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005185RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005186 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005187 Object* obj = args[0];
5188 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5189 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5190 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005191}
5192
5193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005194RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 NoHandleAllocation ha;
5196 ASSERT(args.length() == 1);
5197
5198 return args[0]->ToBoolean();
5199}
5200
5201
5202// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5203// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005204RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205 NoHandleAllocation ha;
5206
5207 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005209 HeapObject* heap_obj = HeapObject::cast(obj);
5210
5211 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005212 if (heap_obj->map()->is_undetectable()) {
5213 return isolate->heap()->undefined_symbol();
5214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215
5216 InstanceType instance_type = heap_obj->map()->instance_type();
5217 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005218 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005219 }
5220
5221 switch (instance_type) {
5222 case ODDBALL_TYPE:
5223 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005224 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225 }
5226 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005227 return FLAG_harmony_typeof
5228 ? isolate->heap()->null_symbol()
5229 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 }
5231 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005233 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005234 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005235 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005236 default:
5237 // For any kind of object not handled above, the spec rule for
5238 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005239 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 }
5241}
5242
5243
lrn@chromium.org25156de2010-04-06 13:10:27 +00005244static bool AreDigits(const char*s, int from, int to) {
5245 for (int i = from; i < to; i++) {
5246 if (s[i] < '0' || s[i] > '9') return false;
5247 }
5248
5249 return true;
5250}
5251
5252
5253static int ParseDecimalInteger(const char*s, int from, int to) {
5254 ASSERT(to - from < 10); // Overflow is not possible.
5255 ASSERT(from < to);
5256 int d = s[from] - '0';
5257
5258 for (int i = from + 1; i < to; i++) {
5259 d = 10 * d + (s[i] - '0');
5260 }
5261
5262 return d;
5263}
5264
5265
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005266RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267 NoHandleAllocation ha;
5268 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005269 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005270 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005271
5272 // Fast case: short integer or some sorts of junk values.
5273 int len = subject->length();
5274 if (subject->IsSeqAsciiString()) {
5275 if (len == 0) return Smi::FromInt(0);
5276
5277 char const* data = SeqAsciiString::cast(subject)->GetChars();
5278 bool minus = (data[0] == '-');
5279 int start_pos = (minus ? 1 : 0);
5280
5281 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005282 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005283 } else if (data[start_pos] > '9') {
5284 // Fast check for a junk value. A valid string may start from a
5285 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5286 // the 'I' character ('Infinity'). All of that have codes not greater than
5287 // '9' except 'I'.
5288 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005289 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005290 }
5291 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5292 // The maximal/minimal smi has 10 digits. If the string has less digits we
5293 // know it will fit into the smi-data type.
5294 int d = ParseDecimalInteger(data, start_pos, len);
5295 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005297 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005298 } else if (!subject->HasHashCode() &&
5299 len <= String::kMaxArrayIndexSize &&
5300 (len == 1 || data[0] != '0')) {
5301 // String hash is not calculated yet but all the data are present.
5302 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005303 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005304#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005305 subject->Hash(); // Force hash calculation.
5306 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5307 static_cast<int>(hash));
5308#endif
5309 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005310 }
5311 return Smi::FromInt(d);
5312 }
5313 }
5314
5315 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005316 return isolate->heap()->NumberFromDouble(
5317 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318}
5319
5320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005321RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322 NoHandleAllocation ha;
5323 ASSERT(args.length() == 1);
5324
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005325 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326 int length = Smi::cast(codes->length())->value();
5327
5328 // Check if the string can be ASCII.
5329 int i;
5330 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005331 Object* element;
5332 { MaybeObject* maybe_element = codes->GetElement(i);
5333 // We probably can't get an exception here, but just in order to enforce
5334 // the checking of inputs in the runtime calls we check here.
5335 if (!maybe_element->ToObject(&element)) return maybe_element;
5336 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005337 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5338 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5339 break;
5340 }
5341
lrn@chromium.org303ada72010-10-27 09:33:13 +00005342 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005343 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005344 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005345 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005346 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005347 }
5348
lrn@chromium.org303ada72010-10-27 09:33:13 +00005349 Object* object = NULL;
5350 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351 String* result = String::cast(object);
5352 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005353 Object* element;
5354 { MaybeObject* maybe_element = codes->GetElement(i);
5355 if (!maybe_element->ToObject(&element)) return maybe_element;
5356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005357 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005358 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005359 }
5360 return result;
5361}
5362
5363
5364// kNotEscaped is generated by the following:
5365//
5366// #!/bin/perl
5367// for (my $i = 0; $i < 256; $i++) {
5368// print "\n" if $i % 16 == 0;
5369// my $c = chr($i);
5370// my $escaped = 1;
5371// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5372// print $escaped ? "0, " : "1, ";
5373// }
5374
5375
5376static bool IsNotEscaped(uint16_t character) {
5377 // Only for 8 bit characters, the rest are always escaped (in a different way)
5378 ASSERT(character < 256);
5379 static const char kNotEscaped[256] = {
5380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5383 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5386 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5387 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5396 };
5397 return kNotEscaped[character] != 0;
5398}
5399
5400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005401RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402 const char hex_chars[] = "0123456789ABCDEF";
5403 NoHandleAllocation ha;
5404 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005405 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005407 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408
5409 int escaped_length = 0;
5410 int length = source->length();
5411 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005412 Access<StringInputBuffer> buffer(
5413 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005414 buffer->Reset(source);
5415 while (buffer->has_more()) {
5416 uint16_t character = buffer->GetNext();
5417 if (character >= 256) {
5418 escaped_length += 6;
5419 } else if (IsNotEscaped(character)) {
5420 escaped_length++;
5421 } else {
5422 escaped_length += 3;
5423 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005424 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005425 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005426 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005427 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005428 return Failure::OutOfMemoryException();
5429 }
5430 }
5431 }
5432 // No length change implies no change. Return original string if no change.
5433 if (escaped_length == length) {
5434 return source;
5435 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005436 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005437 { MaybeObject* maybe_o =
5438 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005439 if (!maybe_o->ToObject(&o)) return maybe_o;
5440 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441 String* destination = String::cast(o);
5442 int dest_position = 0;
5443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005444 Access<StringInputBuffer> buffer(
5445 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005446 buffer->Rewind();
5447 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005448 uint16_t chr = buffer->GetNext();
5449 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005450 destination->Set(dest_position, '%');
5451 destination->Set(dest_position+1, 'u');
5452 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5453 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5454 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5455 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005457 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005458 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459 dest_position++;
5460 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005461 destination->Set(dest_position, '%');
5462 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5463 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005464 dest_position += 3;
5465 }
5466 }
5467 return destination;
5468}
5469
5470
5471static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5472 static const signed char kHexValue['g'] = {
5473 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5474 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5475 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5476 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5477 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5478 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5479 -1, 10, 11, 12, 13, 14, 15 };
5480
5481 if (character1 > 'f') return -1;
5482 int hi = kHexValue[character1];
5483 if (hi == -1) return -1;
5484 if (character2 > 'f') return -1;
5485 int lo = kHexValue[character2];
5486 if (lo == -1) return -1;
5487 return (hi << 4) + lo;
5488}
5489
5490
ager@chromium.org870a0b62008-11-04 11:43:05 +00005491static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005492 int i,
5493 int length,
5494 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005495 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005496 int32_t hi = 0;
5497 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498 if (character == '%' &&
5499 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005500 source->Get(i + 1) == 'u' &&
5501 (hi = TwoDigitHex(source->Get(i + 2),
5502 source->Get(i + 3))) != -1 &&
5503 (lo = TwoDigitHex(source->Get(i + 4),
5504 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 *step = 6;
5506 return (hi << 8) + lo;
5507 } else if (character == '%' &&
5508 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 (lo = TwoDigitHex(source->Get(i + 1),
5510 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 *step = 3;
5512 return lo;
5513 } else {
5514 *step = 1;
5515 return character;
5516 }
5517}
5518
5519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005520RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521 NoHandleAllocation ha;
5522 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005523 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005525 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005526
5527 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005529
5530 int unescaped_length = 0;
5531 for (int i = 0; i < length; unescaped_length++) {
5532 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005533 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005536 i += step;
5537 }
5538
5539 // No length change implies no change. Return original string if no change.
5540 if (unescaped_length == length)
5541 return source;
5542
lrn@chromium.org303ada72010-10-27 09:33:13 +00005543 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005544 { MaybeObject* maybe_o =
5545 ascii ?
5546 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5547 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005548 if (!maybe_o->ToObject(&o)) return maybe_o;
5549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550 String* destination = String::cast(o);
5551
5552 int dest_position = 0;
5553 for (int i = 0; i < length; dest_position++) {
5554 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005555 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 i += step;
5557 }
5558 return destination;
5559}
5560
5561
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005562static const unsigned int kQuoteTableLength = 128u;
5563
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005564static const int kJsonQuotesCharactersPerEntry = 8;
5565static const char* const JsonQuotes =
5566 "\\u0000 \\u0001 \\u0002 \\u0003 "
5567 "\\u0004 \\u0005 \\u0006 \\u0007 "
5568 "\\b \\t \\n \\u000b "
5569 "\\f \\r \\u000e \\u000f "
5570 "\\u0010 \\u0011 \\u0012 \\u0013 "
5571 "\\u0014 \\u0015 \\u0016 \\u0017 "
5572 "\\u0018 \\u0019 \\u001a \\u001b "
5573 "\\u001c \\u001d \\u001e \\u001f "
5574 " ! \\\" # "
5575 "$ % & ' "
5576 "( ) * + "
5577 ", - . / "
5578 "0 1 2 3 "
5579 "4 5 6 7 "
5580 "8 9 : ; "
5581 "< = > ? "
5582 "@ A B C "
5583 "D E F G "
5584 "H I J K "
5585 "L M N O "
5586 "P Q R S "
5587 "T U V W "
5588 "X Y Z [ "
5589 "\\\\ ] ^ _ "
5590 "` a b c "
5591 "d e f g "
5592 "h i j k "
5593 "l m n o "
5594 "p q r s "
5595 "t u v w "
5596 "x y z { "
5597 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005598
5599
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005600// For a string that is less than 32k characters it should always be
5601// possible to allocate it in new space.
5602static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5603
5604
5605// Doing JSON quoting cannot make the string more than this many times larger.
5606static const int kJsonQuoteWorstCaseBlowup = 6;
5607
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005608static const int kSpaceForQuotesAndComma = 3;
5609static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005610
5611// Covers the entire ASCII range (all other characters are unchanged by JSON
5612// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005613static const byte JsonQuoteLengths[kQuoteTableLength] = {
5614 6, 6, 6, 6, 6, 6, 6, 6,
5615 2, 2, 2, 6, 2, 2, 6, 6,
5616 6, 6, 6, 6, 6, 6, 6, 6,
5617 6, 6, 6, 6, 6, 6, 6, 6,
5618 1, 1, 2, 1, 1, 1, 1, 1,
5619 1, 1, 1, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 1, 1, 1, 1,
5623 1, 1, 1, 1, 1, 1, 1, 1,
5624 1, 1, 1, 1, 1, 1, 1, 1,
5625 1, 1, 1, 1, 2, 1, 1, 1,
5626 1, 1, 1, 1, 1, 1, 1, 1,
5627 1, 1, 1, 1, 1, 1, 1, 1,
5628 1, 1, 1, 1, 1, 1, 1, 1,
5629 1, 1, 1, 1, 1, 1, 1, 1,
5630};
5631
5632
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005633template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005634MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005635
5636
5637template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005638MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5639 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005640}
5641
5642
5643template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005644MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5645 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005646}
5647
5648
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005649template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005650static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5651 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005652 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005653 const Char* read_cursor = characters.start();
5654 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005655 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005656 int quoted_length = kSpaceForQuotes;
5657 while (read_cursor < end) {
5658 Char c = *(read_cursor++);
5659 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5660 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005661 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005662 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005663 }
5664 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005665 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5666 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005667 Object* new_object;
5668 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005669 return new_alloc;
5670 }
5671 StringType* new_string = StringType::cast(new_object);
5672
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005673 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005674 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005675 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005676 *(write_cursor++) = '"';
5677
5678 read_cursor = characters.start();
5679 while (read_cursor < end) {
5680 Char c = *(read_cursor++);
5681 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5682 *(write_cursor++) = c;
5683 } else {
5684 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5685 const char* replacement = JsonQuotes +
5686 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5687 for (int i = 0; i < len; i++) {
5688 *write_cursor++ = *replacement++;
5689 }
5690 }
5691 }
5692 *(write_cursor++) = '"';
5693 return new_string;
5694}
5695
5696
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005697template <typename SinkChar, typename SourceChar>
5698static inline SinkChar* WriteQuoteJsonString(
5699 Isolate* isolate,
5700 SinkChar* write_cursor,
5701 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005702 // SinkChar is only char if SourceChar is guaranteed to be char.
5703 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005704 const SourceChar* read_cursor = characters.start();
5705 const SourceChar* end = read_cursor + characters.length();
5706 *(write_cursor++) = '"';
5707 while (read_cursor < end) {
5708 SourceChar c = *(read_cursor++);
5709 if (sizeof(SourceChar) > 1u &&
5710 static_cast<unsigned>(c) >= kQuoteTableLength) {
5711 *(write_cursor++) = static_cast<SinkChar>(c);
5712 } else {
5713 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5714 const char* replacement = JsonQuotes +
5715 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5716 write_cursor[0] = replacement[0];
5717 if (len > 1) {
5718 write_cursor[1] = replacement[1];
5719 if (len > 2) {
5720 ASSERT(len == 6);
5721 write_cursor[2] = replacement[2];
5722 write_cursor[3] = replacement[3];
5723 write_cursor[4] = replacement[4];
5724 write_cursor[5] = replacement[5];
5725 }
5726 }
5727 write_cursor += len;
5728 }
5729 }
5730 *(write_cursor++) = '"';
5731 return write_cursor;
5732}
5733
5734
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005735template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736static MaybeObject* QuoteJsonString(Isolate* isolate,
5737 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005738 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005739 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005740 int worst_case_length =
5741 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005742 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005743 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005744 }
5745
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005746 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5747 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005748 Object* new_object;
5749 if (!new_alloc->ToObject(&new_object)) {
5750 return new_alloc;
5751 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005752 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005753 // Even if our string is small enough to fit in new space we still have to
5754 // handle it being allocated in old space as may happen in the third
5755 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5756 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005757 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005758 }
5759 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005760 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005761
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005762 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005763 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005764 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005765 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5766 write_cursor,
5767 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005768 int final_length = static_cast<int>(
5769 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005770 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005771 isolate->heap()->new_space()->
5772 template ShrinkStringAtAllocationBoundary<StringType>(
5773 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005774 return new_string;
5775}
5776
5777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005778RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005779 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005780 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005781 if (!str->IsFlat()) {
5782 MaybeObject* try_flatten = str->TryFlatten();
5783 Object* flat;
5784 if (!try_flatten->ToObject(&flat)) {
5785 return try_flatten;
5786 }
5787 str = String::cast(flat);
5788 ASSERT(str->IsFlat());
5789 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005790 String::FlatContent flat = str->GetFlatContent();
5791 ASSERT(flat.IsFlat());
5792 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005794 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005795 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005796 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005797 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005798 }
5799}
5800
5801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005802RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005803 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005804 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005805 if (!str->IsFlat()) {
5806 MaybeObject* try_flatten = str->TryFlatten();
5807 Object* flat;
5808 if (!try_flatten->ToObject(&flat)) {
5809 return try_flatten;
5810 }
5811 str = String::cast(flat);
5812 ASSERT(str->IsFlat());
5813 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005814 String::FlatContent flat = str->GetFlatContent();
5815 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005817 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005818 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005819 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005820 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005821 }
5822}
5823
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005824
5825template <typename Char, typename StringType>
5826static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5827 FixedArray* array,
5828 int worst_case_length) {
5829 int length = array->length();
5830
5831 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5832 worst_case_length);
5833 Object* new_object;
5834 if (!new_alloc->ToObject(&new_object)) {
5835 return new_alloc;
5836 }
5837 if (!isolate->heap()->new_space()->Contains(new_object)) {
5838 // Even if our string is small enough to fit in new space we still have to
5839 // handle it being allocated in old space as may happen in the third
5840 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5841 // CEntryStub::GenerateCore.
5842 return isolate->heap()->undefined_value();
5843 }
5844 AssertNoAllocation no_gc;
5845 StringType* new_string = StringType::cast(new_object);
5846 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5847
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005848 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005849 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005850 *(write_cursor++) = '[';
5851 for (int i = 0; i < length; i++) {
5852 if (i != 0) *(write_cursor++) = ',';
5853 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005854 String::FlatContent content = str->GetFlatContent();
5855 ASSERT(content.IsFlat());
5856 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5858 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005859 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005860 } else {
5861 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5862 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005863 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005864 }
5865 }
5866 *(write_cursor++) = ']';
5867
5868 int final_length = static_cast<int>(
5869 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005870 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005871 isolate->heap()->new_space()->
5872 template ShrinkStringAtAllocationBoundary<StringType>(
5873 new_string, final_length);
5874 return new_string;
5875}
5876
5877
5878RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5879 NoHandleAllocation ha;
5880 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005881 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005882
5883 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5884 FixedArray* elements = FixedArray::cast(array->elements());
5885 int n = elements->length();
5886 bool ascii = true;
5887 int total_length = 0;
5888
5889 for (int i = 0; i < n; i++) {
5890 Object* elt = elements->get(i);
5891 if (!elt->IsString()) return isolate->heap()->undefined_value();
5892 String* element = String::cast(elt);
5893 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5894 total_length += element->length();
5895 if (ascii && element->IsTwoByteRepresentation()) {
5896 ascii = false;
5897 }
5898 }
5899
5900 int worst_case_length =
5901 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5902 + total_length * kJsonQuoteWorstCaseBlowup;
5903
5904 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5905 return isolate->heap()->undefined_value();
5906 }
5907
5908 if (ascii) {
5909 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5910 elements,
5911 worst_case_length);
5912 } else {
5913 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5914 elements,
5915 worst_case_length);
5916 }
5917}
5918
5919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005920RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 NoHandleAllocation ha;
5922
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005923 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005924 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005926 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927
lrn@chromium.org25156de2010-04-06 13:10:27 +00005928 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005929 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931}
5932
5933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005934RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005936 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937
5938 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005939 double value = StringToDouble(isolate->unicode_cache(),
5940 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941
5942 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005943 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944}
5945
5946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005948MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005949 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005950 String* s,
5951 int length,
5952 int input_string_length,
5953 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005954 // We try this twice, once with the assumption that the result is no longer
5955 // than the input and, if that assumption breaks, again with the exact
5956 // length. This may not be pretty, but it is nicer than what was here before
5957 // and I hereby claim my vaffel-is.
5958 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 // Allocate the resulting string.
5960 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005961 // NOTE: This assumes that the upper/lower case of an ASCII
5962 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963 // might break in the future if we implement more context and locale
5964 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005965 Object* o;
5966 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005967 ? isolate->heap()->AllocateRawAsciiString(length)
5968 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005969 if (!maybe_o->ToObject(&o)) return maybe_o;
5970 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 String* result = String::cast(o);
5972 bool has_changed_character = false;
5973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974 // Convert all characters to upper case, assuming that they will fit
5975 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 Access<StringInputBuffer> buffer(
5977 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005979 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005980 // We can assume that the string is not empty
5981 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005982 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005983 bool has_next = buffer->has_more();
5984 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985 int char_length = mapping->get(current, next, chars);
5986 if (char_length == 0) {
5987 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005988 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 i++;
5990 } else if (char_length == 1) {
5991 // Common case: converting the letter resulted in one character.
5992 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005993 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 has_changed_character = true;
5995 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005996 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 // We've assumed that the result would be as long as the
5998 // input but here is a character that converts to several
5999 // characters. No matter, we calculate the exact length
6000 // of the result and try the whole thing again.
6001 //
6002 // Note that this leaves room for optimization. We could just
6003 // memcpy what we already have to the result string. Also,
6004 // the result string is the last object allocated we could
6005 // "realloc" it and probably, in the vast majority of cases,
6006 // extend the existing string to be able to hold the full
6007 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006008 int next_length = 0;
6009 if (has_next) {
6010 next_length = mapping->get(next, 0, chars);
6011 if (next_length == 0) next_length = 1;
6012 }
6013 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014 while (buffer->has_more()) {
6015 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006016 // NOTE: we use 0 as the next character here because, while
6017 // the next character may affect what a character converts to,
6018 // it does not in any case affect the length of what it convert
6019 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 int char_length = mapping->get(current, 0, chars);
6021 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006022 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006023 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006024 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006025 return Failure::OutOfMemoryException();
6026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006028 // Try again with the real length.
6029 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 } else {
6031 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006032 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 i++;
6034 }
6035 has_changed_character = true;
6036 }
6037 current = next;
6038 }
6039 if (has_changed_character) {
6040 return result;
6041 } else {
6042 // If we didn't actually change anything in doing the conversion
6043 // we simple return the result and let the converted string
6044 // become garbage; there is no reason to keep two identical strings
6045 // alive.
6046 return s;
6047 }
6048}
6049
6050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006051namespace {
6052
lrn@chromium.org303ada72010-10-27 09:33:13 +00006053static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6054
6055
6056// Given a word and two range boundaries returns a word with high bit
6057// set in every byte iff the corresponding input byte was strictly in
6058// the range (m, n). All the other bits in the result are cleared.
6059// This function is only useful when it can be inlined and the
6060// boundaries are statically known.
6061// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006062// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006063static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006064 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006065 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6066 // Use strict inequalities since in edge cases the function could be
6067 // further simplified.
6068 ASSERT(0 < m && m < n && n < 0x7F);
6069 // Has high bit set in every w byte less than n.
6070 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6071 // Has high bit set in every w byte greater than m.
6072 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6073 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6074}
6075
6076
6077enum AsciiCaseConversion {
6078 ASCII_TO_LOWER,
6079 ASCII_TO_UPPER
6080};
6081
6082
6083template <AsciiCaseConversion dir>
6084struct FastAsciiConverter {
6085 static bool Convert(char* dst, char* src, int length) {
6086#ifdef DEBUG
6087 char* saved_dst = dst;
6088 char* saved_src = src;
6089#endif
6090 // We rely on the distance between upper and lower case letters
6091 // being a known power of 2.
6092 ASSERT('a' - 'A' == (1 << 5));
6093 // Boundaries for the range of input characters than require conversion.
6094 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6095 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6096 bool changed = false;
6097 char* const limit = src + length;
6098#ifdef V8_HOST_CAN_READ_UNALIGNED
6099 // Process the prefix of the input that requires no conversion one
6100 // (machine) word at a time.
6101 while (src <= limit - sizeof(uintptr_t)) {
6102 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6103 if (AsciiRangeMask(w, lo, hi) != 0) {
6104 changed = true;
6105 break;
6106 }
6107 *reinterpret_cast<uintptr_t*>(dst) = w;
6108 src += sizeof(uintptr_t);
6109 dst += sizeof(uintptr_t);
6110 }
6111 // Process the remainder of the input performing conversion when
6112 // required one word at a time.
6113 while (src <= limit - sizeof(uintptr_t)) {
6114 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6115 uintptr_t m = AsciiRangeMask(w, lo, hi);
6116 // The mask has high (7th) bit set in every byte that needs
6117 // conversion and we know that the distance between cases is
6118 // 1 << 5.
6119 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6120 src += sizeof(uintptr_t);
6121 dst += sizeof(uintptr_t);
6122 }
6123#endif
6124 // Process the last few bytes of the input (or the whole input if
6125 // unaligned access is not supported).
6126 while (src < limit) {
6127 char c = *src;
6128 if (lo < c && c < hi) {
6129 c ^= (1 << 5);
6130 changed = true;
6131 }
6132 *dst = c;
6133 ++src;
6134 ++dst;
6135 }
6136#ifdef DEBUG
6137 CheckConvert(saved_dst, saved_src, length, changed);
6138#endif
6139 return changed;
6140 }
6141
6142#ifdef DEBUG
6143 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6144 bool expected_changed = false;
6145 for (int i = 0; i < length; i++) {
6146 if (dst[i] == src[i]) continue;
6147 expected_changed = true;
6148 if (dir == ASCII_TO_LOWER) {
6149 ASSERT('A' <= src[i] && src[i] <= 'Z');
6150 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6151 } else {
6152 ASSERT(dir == ASCII_TO_UPPER);
6153 ASSERT('a' <= src[i] && src[i] <= 'z');
6154 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6155 }
6156 }
6157 ASSERT(expected_changed == changed);
6158 }
6159#endif
6160};
6161
6162
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006163struct ToLowerTraits {
6164 typedef unibrow::ToLowercase UnibrowConverter;
6165
lrn@chromium.org303ada72010-10-27 09:33:13 +00006166 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167};
6168
6169
6170struct ToUpperTraits {
6171 typedef unibrow::ToUppercase UnibrowConverter;
6172
lrn@chromium.org303ada72010-10-27 09:33:13 +00006173 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006174};
6175
6176} // namespace
6177
6178
6179template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006181 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006183 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006184 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006185 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006186 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006187
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006188 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006189 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006190 if (length == 0) return s;
6191
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006192 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006193 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006194 // NOTE: This assumes that the upper/lower case of an ASCII
6195 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196 // might break in the future if we implement more context and locale
6197 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006198 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006199 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006200 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006201 if (!maybe_o->ToObject(&o)) return maybe_o;
6202 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006203 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006204 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006205 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006206 return has_changed_character ? result : s;
6207 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006208
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 { MaybeObject* maybe_answer =
6211 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006212 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006214 if (answer->IsSmi()) {
6215 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006216 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006217 ConvertCaseHelper(isolate,
6218 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006219 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6220 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006221 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006222 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006223}
6224
6225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006226RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006227 return ConvertCase<ToLowerTraits>(
6228 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229}
6230
6231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006232RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 return ConvertCase<ToUpperTraits>(
6234 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006235}
6236
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006237
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006238static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006239 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006240}
6241
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006243RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006244 NoHandleAllocation ha;
6245 ASSERT(args.length() == 3);
6246
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006247 CONVERT_ARG_CHECKED(String, s, 0);
6248 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6249 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006250
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006251 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006252 int length = s->length();
6253
6254 int left = 0;
6255 if (trimLeft) {
6256 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6257 left++;
6258 }
6259 }
6260
6261 int right = length;
6262 if (trimRight) {
6263 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6264 right--;
6265 }
6266 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006267 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006268}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006271RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006272 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006273 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006274 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6275 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006276 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6277
6278 int subject_length = subject->length();
6279 int pattern_length = pattern->length();
6280 RUNTIME_ASSERT(pattern_length > 0);
6281
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006282 if (limit == 0xffffffffu) {
6283 Handle<Object> cached_answer(StringSplitCache::Lookup(
6284 isolate->heap()->string_split_cache(),
6285 *subject,
6286 *pattern));
6287 if (*cached_answer != Smi::FromInt(0)) {
6288 Handle<JSArray> result =
6289 isolate->factory()->NewJSArrayWithElements(
6290 Handle<FixedArray>::cast(cached_answer));
6291 return *result;
6292 }
6293 }
6294
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006295 // The limit can be very large (0xffffffffu), but since the pattern
6296 // isn't empty, we can never create more parts than ~half the length
6297 // of the subject.
6298
6299 if (!subject->IsFlat()) FlattenString(subject);
6300
6301 static const int kMaxInitialListCapacity = 16;
6302
danno@chromium.org40cb8782011-05-25 07:58:50 +00006303 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006304
6305 // Find (up to limit) indices of separator and end-of-string in subject
6306 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6307 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006308 if (!pattern->IsFlat()) FlattenString(pattern);
6309
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006310 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006311
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006312 if (static_cast<uint32_t>(indices.length()) < limit) {
6313 indices.Add(subject_length);
6314 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006315
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006316 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006317
6318 // Create JSArray of substrings separated by separator.
6319 int part_count = indices.length();
6320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006321 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006322 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006323 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006324 result->set_length(Smi::FromInt(part_count));
6325
6326 ASSERT(result->HasFastElements());
6327
6328 if (part_count == 1 && indices.at(0) == subject_length) {
6329 FixedArray::cast(result->elements())->set(0, *subject);
6330 return *result;
6331 }
6332
6333 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6334 int part_start = 0;
6335 for (int i = 0; i < part_count; i++) {
6336 HandleScope local_loop_handle;
6337 int part_end = indices.at(i);
6338 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006339 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006340 elements->set(i, *substring);
6341 part_start = part_end + pattern_length;
6342 }
6343
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006344 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006345 if (result->HasFastElements()) {
6346 StringSplitCache::Enter(isolate->heap(),
6347 isolate->heap()->string_split_cache(),
6348 *subject,
6349 *pattern,
6350 *elements);
6351 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006352 }
6353
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006354 return *result;
6355}
6356
6357
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006358// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006359// one-char strings in the cache. Gives up on the first char that is
6360// not in the cache and fills the remainder with smi zeros. Returns
6361// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362static int CopyCachedAsciiCharsToArray(Heap* heap,
6363 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006364 FixedArray* elements,
6365 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006366 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006367 FixedArray* ascii_cache = heap->single_character_string_cache();
6368 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006370 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006371 for (i = 0; i < length; ++i) {
6372 Object* value = ascii_cache->get(chars[i]);
6373 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006374 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006375 }
6376 if (i < length) {
6377 ASSERT(Smi::FromInt(0) == 0);
6378 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6379 }
6380#ifdef DEBUG
6381 for (int j = 0; j < length; ++j) {
6382 Object* element = elements->get(j);
6383 ASSERT(element == Smi::FromInt(0) ||
6384 (element->IsString() && String::cast(element)->LooksValid()));
6385 }
6386#endif
6387 return i;
6388}
6389
6390
6391// Converts a String to JSArray.
6392// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006393RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006394 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006395 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006396 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006397 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006398
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006399 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006400 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401
6402 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006403 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006404 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006405 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006406 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006407 { MaybeObject* maybe_obj =
6408 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006409 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6410 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006411 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006412 String::FlatContent content = s->GetFlatContent();
6413 if (content.IsAscii()) {
6414 Vector<const char> chars = content.ToAsciiVector();
6415 // Note, this will initialize all elements (not only the prefix)
6416 // to prevent GC from seeing partially initialized array.
6417 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6418 chars.start(),
6419 *elements,
6420 length);
6421 } else {
6422 MemsetPointer(elements->data_start(),
6423 isolate->heap()->undefined_value(),
6424 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006425 }
6426 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006427 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006428 }
6429 for (int i = position; i < length; ++i) {
6430 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6431 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006432 }
6433
6434#ifdef DEBUG
6435 for (int i = 0; i < length; ++i) {
6436 ASSERT(String::cast(elements->get(i))->length() == 1);
6437 }
6438#endif
6439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006441}
6442
6443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006444RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006445 NoHandleAllocation ha;
6446 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006447 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006448 return value->ToObject();
6449}
6450
6451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006453 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006455 return char_length == 0;
6456}
6457
6458
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006459RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460 NoHandleAllocation ha;
6461 ASSERT(args.length() == 1);
6462
6463 Object* number = args[0];
6464 RUNTIME_ASSERT(number->IsNumber());
6465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006466 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006467}
6468
6469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006470RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006471 NoHandleAllocation ha;
6472 ASSERT(args.length() == 1);
6473
6474 Object* number = args[0];
6475 RUNTIME_ASSERT(number->IsNumber());
6476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006478}
6479
6480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006481RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482 NoHandleAllocation ha;
6483 ASSERT(args.length() == 1);
6484
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006485 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006486
6487 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6488 if (number > 0 && number <= Smi::kMaxValue) {
6489 return Smi::FromInt(static_cast<int>(number));
6490 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 1);
6498
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006499 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006500
6501 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6502 if (number > 0 && number <= Smi::kMaxValue) {
6503 return Smi::FromInt(static_cast<int>(number));
6504 }
6505
6506 double double_value = DoubleToInteger(number);
6507 // Map both -0 and +0 to +0.
6508 if (double_value == 0) double_value = 0;
6509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006510 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006511}
6512
6513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006514RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515 NoHandleAllocation ha;
6516 ASSERT(args.length() == 1);
6517
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006518 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006519 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006520}
6521
6522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006523RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006524 NoHandleAllocation ha;
6525 ASSERT(args.length() == 1);
6526
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006527 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006528
6529 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6530 if (number > 0 && number <= Smi::kMaxValue) {
6531 return Smi::FromInt(static_cast<int>(number));
6532 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006533 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534}
6535
6536
ager@chromium.org870a0b62008-11-04 11:43:05 +00006537// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6538// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006539RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006540 NoHandleAllocation ha;
6541 ASSERT(args.length() == 1);
6542
6543 Object* obj = args[0];
6544 if (obj->IsSmi()) {
6545 return obj;
6546 }
6547 if (obj->IsHeapNumber()) {
6548 double value = HeapNumber::cast(obj)->value();
6549 int int_value = FastD2I(value);
6550 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6551 return Smi::FromInt(int_value);
6552 }
6553 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006554 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006555}
6556
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006558RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006559 NoHandleAllocation ha;
6560 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006562}
6563
6564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006565RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 NoHandleAllocation ha;
6567 ASSERT(args.length() == 2);
6568
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006569 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6570 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006571 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572}
6573
6574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006575RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 NoHandleAllocation ha;
6577 ASSERT(args.length() == 2);
6578
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006579 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6580 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582}
6583
6584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586 NoHandleAllocation ha;
6587 ASSERT(args.length() == 2);
6588
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006589 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6590 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006591 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592}
6593
6594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006595RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596 NoHandleAllocation ha;
6597 ASSERT(args.length() == 1);
6598
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006599 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006600 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601}
6602
6603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006604RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006605 NoHandleAllocation ha;
6606 ASSERT(args.length() == 0);
6607
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006609}
6610
6611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006612RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613 NoHandleAllocation ha;
6614 ASSERT(args.length() == 2);
6615
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006616 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6617 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006618 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619}
6620
6621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006622RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623 NoHandleAllocation ha;
6624 ASSERT(args.length() == 2);
6625
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006626 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6627 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628
ager@chromium.org3811b432009-10-28 14:53:37 +00006629 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006630 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006631 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632}
6633
6634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006635RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636 NoHandleAllocation ha;
6637 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006638 CONVERT_ARG_CHECKED(String, str1, 0);
6639 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006640 isolate->counters()->string_add_runtime()->Increment();
6641 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642}
6643
6644
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006645template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006646static inline void StringBuilderConcatHelper(String* special,
6647 sinkchar* sink,
6648 FixedArray* fixed_array,
6649 int array_length) {
6650 int position = 0;
6651 for (int i = 0; i < array_length; i++) {
6652 Object* element = fixed_array->get(i);
6653 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006654 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006655 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006656 int pos;
6657 int len;
6658 if (encoded_slice > 0) {
6659 // Position and length encoded in one smi.
6660 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6661 len = StringBuilderSubstringLength::decode(encoded_slice);
6662 } else {
6663 // Position and length encoded in two smis.
6664 Object* obj = fixed_array->get(++i);
6665 ASSERT(obj->IsSmi());
6666 pos = Smi::cast(obj)->value();
6667 len = -encoded_slice;
6668 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006669 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006670 sink + position,
6671 pos,
6672 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006673 position += len;
6674 } else {
6675 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006676 int element_length = string->length();
6677 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006678 position += element_length;
6679 }
6680 }
6681}
6682
6683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006684RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006686 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006687 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006688 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006690 return Failure::OutOfMemoryException();
6691 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006692 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006693 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006694
6695 // This assumption is used by the slice encoding in one or two smis.
6696 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6697
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006698 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006699 if (maybe_result->IsFailure()) return maybe_result;
6700
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006701 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006704 }
6705 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006706 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709
6710 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006711 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712 } else if (array_length == 1) {
6713 Object* first = fixed_array->get(0);
6714 if (first->IsString()) return first;
6715 }
6716
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006717 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 int position = 0;
6719 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006720 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 Object* elt = fixed_array->get(i);
6722 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006723 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006724 int smi_value = Smi::cast(elt)->value();
6725 int pos;
6726 int len;
6727 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006728 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006729 pos = StringBuilderSubstringPosition::decode(smi_value);
6730 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006731 } else {
6732 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006733 len = -smi_value;
6734 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006735 i++;
6736 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006737 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006738 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006739 Object* next_smi = fixed_array->get(i);
6740 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006741 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006742 }
6743 pos = Smi::cast(next_smi)->value();
6744 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006745 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006748 ASSERT(pos >= 0);
6749 ASSERT(len >= 0);
6750 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006752 }
6753 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 } else if (elt->IsString()) {
6755 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006756 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006757 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006758 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006760 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006764 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006765 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006766 return Failure::OutOfMemoryException();
6767 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006768 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 }
6770
6771 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006773
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006774 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006775 { MaybeObject* maybe_object =
6776 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006777 if (!maybe_object->ToObject(&object)) return maybe_object;
6778 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006779 SeqAsciiString* answer = SeqAsciiString::cast(object);
6780 StringBuilderConcatHelper(special,
6781 answer->GetChars(),
6782 fixed_array,
6783 array_length);
6784 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006785 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 { MaybeObject* maybe_object =
6787 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006788 if (!maybe_object->ToObject(&object)) return maybe_object;
6789 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006790 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6791 StringBuilderConcatHelper(special,
6792 answer->GetChars(),
6793 fixed_array,
6794 array_length);
6795 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797}
6798
6799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006800RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006801 NoHandleAllocation ha;
6802 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006803 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006804 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006805 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006806 return Failure::OutOfMemoryException();
6807 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006808 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006809 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006810
6811 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006812 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006813 }
6814 FixedArray* fixed_array = FixedArray::cast(array->elements());
6815 if (fixed_array->length() < array_length) {
6816 array_length = fixed_array->length();
6817 }
6818
6819 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006820 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006821 } else if (array_length == 1) {
6822 Object* first = fixed_array->get(0);
6823 if (first->IsString()) return first;
6824 }
6825
6826 int separator_length = separator->length();
6827 int max_nof_separators =
6828 (String::kMaxLength + separator_length - 1) / separator_length;
6829 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006830 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006831 return Failure::OutOfMemoryException();
6832 }
6833 int length = (array_length - 1) * separator_length;
6834 for (int i = 0; i < array_length; i++) {
6835 Object* element_obj = fixed_array->get(i);
6836 if (!element_obj->IsString()) {
6837 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006839 }
6840 String* element = String::cast(element_obj);
6841 int increment = element->length();
6842 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006843 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006844 return Failure::OutOfMemoryException();
6845 }
6846 length += increment;
6847 }
6848
6849 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006850 { MaybeObject* maybe_object =
6851 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006852 if (!maybe_object->ToObject(&object)) return maybe_object;
6853 }
6854 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6855
6856 uc16* sink = answer->GetChars();
6857#ifdef DEBUG
6858 uc16* end = sink + length;
6859#endif
6860
6861 String* first = String::cast(fixed_array->get(0));
6862 int first_length = first->length();
6863 String::WriteToFlat(first, sink, 0, first_length);
6864 sink += first_length;
6865
6866 for (int i = 1; i < array_length; i++) {
6867 ASSERT(sink + separator_length <= end);
6868 String::WriteToFlat(separator, sink, 0, separator_length);
6869 sink += separator_length;
6870
6871 String* element = String::cast(fixed_array->get(i));
6872 int element_length = element->length();
6873 ASSERT(sink + element_length <= end);
6874 String::WriteToFlat(element, sink, 0, element_length);
6875 sink += element_length;
6876 }
6877 ASSERT(sink == end);
6878
6879 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6880 return answer;
6881}
6882
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006883template <typename Char>
6884static void JoinSparseArrayWithSeparator(FixedArray* elements,
6885 int elements_length,
6886 uint32_t array_length,
6887 String* separator,
6888 Vector<Char> buffer) {
6889 int previous_separator_position = 0;
6890 int separator_length = separator->length();
6891 int cursor = 0;
6892 for (int i = 0; i < elements_length; i += 2) {
6893 int position = NumberToInt32(elements->get(i));
6894 String* string = String::cast(elements->get(i + 1));
6895 int string_length = string->length();
6896 if (string->length() > 0) {
6897 while (previous_separator_position < position) {
6898 String::WriteToFlat<Char>(separator, &buffer[cursor],
6899 0, separator_length);
6900 cursor += separator_length;
6901 previous_separator_position++;
6902 }
6903 String::WriteToFlat<Char>(string, &buffer[cursor],
6904 0, string_length);
6905 cursor += string->length();
6906 }
6907 }
6908 if (separator_length > 0) {
6909 // Array length must be representable as a signed 32-bit number,
6910 // otherwise the total string length would have been too large.
6911 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6912 int last_array_index = static_cast<int>(array_length - 1);
6913 while (previous_separator_position < last_array_index) {
6914 String::WriteToFlat<Char>(separator, &buffer[cursor],
6915 0, separator_length);
6916 cursor += separator_length;
6917 previous_separator_position++;
6918 }
6919 }
6920 ASSERT(cursor <= buffer.length());
6921}
6922
6923
6924RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6925 NoHandleAllocation ha;
6926 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006927 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006928 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6929 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006930 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006931 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006932 // elements_array is fast-mode JSarray of alternating positions
6933 // (increasing order) and strings.
6934 // array_length is length of original array (used to add separators);
6935 // separator is string to put between elements. Assumed to be non-empty.
6936
6937 // Find total length of join result.
6938 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006939 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006940 int max_string_length;
6941 if (is_ascii) {
6942 max_string_length = SeqAsciiString::kMaxLength;
6943 } else {
6944 max_string_length = SeqTwoByteString::kMaxLength;
6945 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006946 bool overflow = false;
6947 CONVERT_NUMBER_CHECKED(int, elements_length,
6948 Int32, elements_array->length());
6949 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6950 FixedArray* elements = FixedArray::cast(elements_array->elements());
6951 for (int i = 0; i < elements_length; i += 2) {
6952 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006953 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6954 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006955 int length = string->length();
6956 if (is_ascii && !string->IsAsciiRepresentation()) {
6957 is_ascii = false;
6958 max_string_length = SeqTwoByteString::kMaxLength;
6959 }
6960 if (length > max_string_length ||
6961 max_string_length - length < string_length) {
6962 overflow = true;
6963 break;
6964 }
6965 string_length += length;
6966 }
6967 int separator_length = separator->length();
6968 if (!overflow && separator_length > 0) {
6969 if (array_length <= 0x7fffffffu) {
6970 int separator_count = static_cast<int>(array_length) - 1;
6971 int remaining_length = max_string_length - string_length;
6972 if ((remaining_length / separator_length) >= separator_count) {
6973 string_length += separator_length * (array_length - 1);
6974 } else {
6975 // Not room for the separators within the maximal string length.
6976 overflow = true;
6977 }
6978 } else {
6979 // Nonempty separator and at least 2^31-1 separators necessary
6980 // means that the string is too large to create.
6981 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6982 overflow = true;
6983 }
6984 }
6985 if (overflow) {
6986 // Throw OutOfMemory exception for creating too large a string.
6987 V8::FatalProcessOutOfMemory("Array join result too large.");
6988 }
6989
6990 if (is_ascii) {
6991 MaybeObject* result_allocation =
6992 isolate->heap()->AllocateRawAsciiString(string_length);
6993 if (result_allocation->IsFailure()) return result_allocation;
6994 SeqAsciiString* result_string =
6995 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6996 JoinSparseArrayWithSeparator<char>(elements,
6997 elements_length,
6998 array_length,
6999 separator,
7000 Vector<char>(result_string->GetChars(),
7001 string_length));
7002 return result_string;
7003 } else {
7004 MaybeObject* result_allocation =
7005 isolate->heap()->AllocateRawTwoByteString(string_length);
7006 if (result_allocation->IsFailure()) return result_allocation;
7007 SeqTwoByteString* result_string =
7008 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7009 JoinSparseArrayWithSeparator<uc16>(elements,
7010 elements_length,
7011 array_length,
7012 separator,
7013 Vector<uc16>(result_string->GetChars(),
7014 string_length));
7015 return result_string;
7016 }
7017}
7018
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007020RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021 NoHandleAllocation ha;
7022 ASSERT(args.length() == 2);
7023
7024 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7025 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007026 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027}
7028
7029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007030RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031 NoHandleAllocation ha;
7032 ASSERT(args.length() == 2);
7033
7034 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7035 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007036 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007037}
7038
7039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007040RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041 NoHandleAllocation ha;
7042 ASSERT(args.length() == 2);
7043
7044 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7045 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007046 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047}
7048
7049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007050RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051 NoHandleAllocation ha;
7052 ASSERT(args.length() == 1);
7053
7054 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007055 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056}
7057
7058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007059RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060 NoHandleAllocation ha;
7061 ASSERT(args.length() == 2);
7062
7063 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7064 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007065 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066}
7067
7068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007069RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070 NoHandleAllocation ha;
7071 ASSERT(args.length() == 2);
7072
7073 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7074 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007075 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007076}
7077
7078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007079RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080 NoHandleAllocation ha;
7081 ASSERT(args.length() == 2);
7082
7083 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7084 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007085 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007086}
7087
7088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007089RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090 NoHandleAllocation ha;
7091 ASSERT(args.length() == 2);
7092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007093 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7094 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007095 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7096 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7097 if (x == y) return Smi::FromInt(EQUAL);
7098 Object* result;
7099 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7100 result = Smi::FromInt(EQUAL);
7101 } else {
7102 result = Smi::FromInt(NOT_EQUAL);
7103 }
7104 return result;
7105}
7106
7107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007108RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007109 NoHandleAllocation ha;
7110 ASSERT(args.length() == 2);
7111
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007112 CONVERT_ARG_CHECKED(String, x, 0);
7113 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007115 bool not_equal = !x->Equals(y);
7116 // This is slightly convoluted because the value that signifies
7117 // equality is 0 and inequality is 1 so we have to negate the result
7118 // from String::Equals.
7119 ASSERT(not_equal == 0 || not_equal == 1);
7120 STATIC_CHECK(EQUAL == 0);
7121 STATIC_CHECK(NOT_EQUAL == 1);
7122 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007123}
7124
7125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007126RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127 NoHandleAllocation ha;
7128 ASSERT(args.length() == 3);
7129
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007130 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7131 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007132 if (isnan(x) || isnan(y)) return args[2];
7133 if (x == y) return Smi::FromInt(EQUAL);
7134 if (isless(x, y)) return Smi::FromInt(LESS);
7135 return Smi::FromInt(GREATER);
7136}
7137
7138
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007139// Compare two Smis as if they were converted to strings and then
7140// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007141RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007142 NoHandleAllocation ha;
7143 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007144 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7145 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007146
7147 // If the integers are equal so are the string representations.
7148 if (x_value == y_value) return Smi::FromInt(EQUAL);
7149
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007150 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007151 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007152 if (x_value == 0 || y_value == 0)
7153 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007154
ager@chromium.org32912102009-01-16 10:38:43 +00007155 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007156 // smallest because the char code of '-' is less than the char code
7157 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007158
7159 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7160 // architectures using 32-bit Smis.
7161 uint32_t x_scaled = x_value;
7162 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007163 if (x_value < 0 || y_value < 0) {
7164 if (y_value >= 0) return Smi::FromInt(LESS);
7165 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007166 x_scaled = -x_value;
7167 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007168 }
7169
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007170 static const uint32_t kPowersOf10[] = {
7171 1, 10, 100, 1000, 10*1000, 100*1000,
7172 1000*1000, 10*1000*1000, 100*1000*1000,
7173 1000*1000*1000
7174 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007175
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007176 // If the integers have the same number of decimal digits they can be
7177 // compared directly as the numeric order is the same as the
7178 // lexicographic order. If one integer has fewer digits, it is scaled
7179 // by some power of 10 to have the same number of digits as the longer
7180 // integer. If the scaled integers are equal it means the shorter
7181 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007182
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007183 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7184 int x_log2 = IntegerLog2(x_scaled);
7185 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7186 x_log10 -= x_scaled < kPowersOf10[x_log10];
7187
7188 int y_log2 = IntegerLog2(y_scaled);
7189 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7190 y_log10 -= y_scaled < kPowersOf10[y_log10];
7191
7192 int tie = EQUAL;
7193
7194 if (x_log10 < y_log10) {
7195 // X has fewer digits. We would like to simply scale up X but that
7196 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7197 // be scaled up to 9_000_000_000. So we scale up by the next
7198 // smallest power and scale down Y to drop one digit. It is OK to
7199 // drop one digit from the longer integer since the final digit is
7200 // past the length of the shorter integer.
7201 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7202 y_scaled /= 10;
7203 tie = LESS;
7204 } else if (y_log10 < x_log10) {
7205 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7206 x_scaled /= 10;
7207 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007208 }
7209
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007210 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7211 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7212 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007213}
7214
7215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007216static Object* StringInputBufferCompare(RuntimeState* state,
7217 String* x,
7218 String* y) {
7219 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7220 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007221 bufx.Reset(x);
7222 bufy.Reset(y);
7223 while (bufx.has_more() && bufy.has_more()) {
7224 int d = bufx.GetNext() - bufy.GetNext();
7225 if (d < 0) return Smi::FromInt(LESS);
7226 else if (d > 0) return Smi::FromInt(GREATER);
7227 }
7228
7229 // x is (non-trivial) prefix of y:
7230 if (bufy.has_more()) return Smi::FromInt(LESS);
7231 // y is prefix of x:
7232 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7233}
7234
7235
7236static Object* FlatStringCompare(String* x, String* y) {
7237 ASSERT(x->IsFlat());
7238 ASSERT(y->IsFlat());
7239 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7240 int prefix_length = x->length();
7241 if (y->length() < prefix_length) {
7242 prefix_length = y->length();
7243 equal_prefix_result = Smi::FromInt(GREATER);
7244 } else if (y->length() > prefix_length) {
7245 equal_prefix_result = Smi::FromInt(LESS);
7246 }
7247 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007248 String::FlatContent x_content = x->GetFlatContent();
7249 String::FlatContent y_content = y->GetFlatContent();
7250 if (x_content.IsAscii()) {
7251 Vector<const char> x_chars = x_content.ToAsciiVector();
7252 if (y_content.IsAscii()) {
7253 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007254 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007255 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007256 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007257 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7258 }
7259 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007260 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7261 if (y_content.IsAscii()) {
7262 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007263 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7264 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007265 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007266 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7267 }
7268 }
7269 Object* result;
7270 if (r == 0) {
7271 result = equal_prefix_result;
7272 } else {
7273 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7274 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007275 ASSERT(result ==
7276 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007277 return result;
7278}
7279
7280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007281RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007282 NoHandleAllocation ha;
7283 ASSERT(args.length() == 2);
7284
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007285 CONVERT_ARG_CHECKED(String, x, 0);
7286 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 // A few fast case tests before we flatten.
7291 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007292 if (y->length() == 0) {
7293 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007295 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007296 return Smi::FromInt(LESS);
7297 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007298
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007299 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007300 if (d < 0) return Smi::FromInt(LESS);
7301 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007302
lrn@chromium.org303ada72010-10-27 09:33:13 +00007303 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007304 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007305 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7306 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007307 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007308 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7309 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007310
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007311 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007312 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313}
7314
7315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007316RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317 NoHandleAllocation ha;
7318 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007320
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007321 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007323}
7324
7325
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007326RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327 NoHandleAllocation ha;
7328 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007329 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007330
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007331 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007332 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333}
7334
7335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007336RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337 NoHandleAllocation ha;
7338 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007341 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007342 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343}
7344
7345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346static const double kPiDividedBy4 = 0.78539816339744830962;
7347
7348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007349RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 NoHandleAllocation ha;
7351 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007352 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007354 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7355 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356 double result;
7357 if (isinf(x) && isinf(y)) {
7358 // Make sure that the result in case of two infinite arguments
7359 // is a multiple of Pi / 4. The sign of the result is determined
7360 // by the first argument (x) and the sign of the second argument
7361 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362 int multiplier = (x < 0) ? -1 : 1;
7363 if (y < 0) multiplier *= 3;
7364 result = multiplier * kPiDividedBy4;
7365 } else {
7366 result = atan2(x, y);
7367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007368 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369}
7370
7371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007372RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373 NoHandleAllocation ha;
7374 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007375 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007377 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379}
7380
7381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007382RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383 NoHandleAllocation ha;
7384 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007385 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007387 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389}
7390
7391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007392RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 NoHandleAllocation ha;
7394 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007395 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007397 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007398 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007399}
7400
7401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007402RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403 NoHandleAllocation ha;
7404 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007405 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007407 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007408 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409}
7410
7411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007412RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 NoHandleAllocation ha;
7414 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007415 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007417 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419}
7420
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007421// Slow version of Math.pow. We check for fast paths for special cases.
7422// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424 NoHandleAllocation ha;
7425 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007426 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007428 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007429
7430 // If the second argument is a smi, it is much faster to call the
7431 // custom powi() function than the generic pow().
7432 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007433 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007434 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007435 }
7436
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007437 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007438 int y_int = static_cast<int>(y);
7439 double result;
7440 if (y == y_int) {
7441 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7442 } else if (y == 0.5) {
7443 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7444 } else if (y == -0.5) {
7445 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7446 } else {
7447 result = power_double_double(x, y);
7448 }
7449 if (isnan(result)) return isolate->heap()->nan_value();
7450 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451}
7452
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007453// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007454// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007455RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007456 NoHandleAllocation ha;
7457 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007458 isolate->counters()->math_pow()->Increment();
7459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007460 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7461 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007462 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007463 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007464 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007465 double result = power_double_double(x, y);
7466 if (isnan(result)) return isolate->heap()->nan_value();
7467 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007468 }
7469}
7470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007472RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473 NoHandleAllocation ha;
7474 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007475 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007477 if (!args[0]->IsHeapNumber()) {
7478 // Must be smi. Return the argument unchanged for all the other types
7479 // to make fuzz-natives test happy.
7480 return args[0];
7481 }
7482
7483 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7484
7485 double value = number->value();
7486 int exponent = number->get_exponent();
7487 int sign = number->get_sign();
7488
danno@chromium.org160a7b02011-04-18 15:51:38 +00007489 if (exponent < -1) {
7490 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7491 if (sign) return isolate->heap()->minus_zero_value();
7492 return Smi::FromInt(0);
7493 }
7494
7495 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7496 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007497 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007498 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007499 return Smi::FromInt(static_cast<int>(value + 0.5));
7500 }
7501
7502 // If the magnitude is big enough, there's no place for fraction part. If we
7503 // try to add 0.5 to this number, 1.0 will be added instead.
7504 if (exponent >= 52) {
7505 return number;
7506 }
7507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007508 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007509
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007510 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512}
7513
7514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007515RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516 NoHandleAllocation ha;
7517 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007518 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007520 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522}
7523
7524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007525RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526 NoHandleAllocation ha;
7527 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007528 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007529
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007530 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532}
7533
7534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007535RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007536 NoHandleAllocation ha;
7537 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007540 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007541 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542}
7543
7544
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007545static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007546 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7547 181, 212, 243, 273, 304, 334};
7548 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7549 182, 213, 244, 274, 305, 335};
7550
7551 year += month / 12;
7552 month %= 12;
7553 if (month < 0) {
7554 year--;
7555 month += 12;
7556 }
7557
7558 ASSERT(month >= 0);
7559 ASSERT(month < 12);
7560
7561 // year_delta is an arbitrary number such that:
7562 // a) year_delta = -1 (mod 400)
7563 // b) year + year_delta > 0 for years in the range defined by
7564 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7565 // Jan 1 1970. This is required so that we don't run into integer
7566 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007567 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007568 // operations.
7569 static const int year_delta = 399999;
7570 static const int base_day = 365 * (1970 + year_delta) +
7571 (1970 + year_delta) / 4 -
7572 (1970 + year_delta) / 100 +
7573 (1970 + year_delta) / 400;
7574
7575 int year1 = year + year_delta;
7576 int day_from_year = 365 * year1 +
7577 year1 / 4 -
7578 year1 / 100 +
7579 year1 / 400 -
7580 base_day;
7581
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007582 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7583 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007584 }
7585
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007586 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007587}
7588
7589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007590RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007591 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007592 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007593
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007594 CONVERT_SMI_ARG_CHECKED(year, 0);
7595 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007596
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007597 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007598}
7599
7600
7601static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7602static const int kDaysIn4Years = 4 * 365 + 1;
7603static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7604static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7605static const int kDays1970to2000 = 30 * 365 + 7;
7606static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7607 kDays1970to2000;
7608static const int kYearsOffset = 400000;
7609
7610static const char kDayInYear[] = {
7611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7612 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7613 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7614 22, 23, 24, 25, 26, 27, 28,
7615 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7616 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7618 22, 23, 24, 25, 26, 27, 28, 29, 30,
7619 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7620 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7621 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7622 22, 23, 24, 25, 26, 27, 28, 29, 30,
7623 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7624 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7625 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7626 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7627 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7628 22, 23, 24, 25, 26, 27, 28, 29, 30,
7629 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7630 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7631 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7632 22, 23, 24, 25, 26, 27, 28, 29, 30,
7633 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7634 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7635
7636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7637 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7638 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7639 22, 23, 24, 25, 26, 27, 28,
7640 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7641 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7642 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7643 22, 23, 24, 25, 26, 27, 28, 29, 30,
7644 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7645 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7646 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7647 22, 23, 24, 25, 26, 27, 28, 29, 30,
7648 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7649 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7650 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7651 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7652 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7653 22, 23, 24, 25, 26, 27, 28, 29, 30,
7654 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7655 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7656 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7657 22, 23, 24, 25, 26, 27, 28, 29, 30,
7658 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7659 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7660
7661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7662 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7663 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7664 22, 23, 24, 25, 26, 27, 28, 29,
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28, 29, 30,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7685
7686 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7687 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7688 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7689 22, 23, 24, 25, 26, 27, 28,
7690 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7691 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7692 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7693 22, 23, 24, 25, 26, 27, 28, 29, 30,
7694 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7695 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7696 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7697 22, 23, 24, 25, 26, 27, 28, 29, 30,
7698 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7699 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7700 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7701 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7706 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7707 22, 23, 24, 25, 26, 27, 28, 29, 30,
7708 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7709 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7710
7711static const char kMonthInYear[] = {
7712 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7713 0, 0, 0, 0, 0, 0,
7714 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7715 1, 1, 1,
7716 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7717 2, 2, 2, 2, 2, 2,
7718 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7719 3, 3, 3, 3, 3,
7720 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7721 4, 4, 4, 4, 4, 4,
7722 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7723 5, 5, 5, 5, 5,
7724 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7725 6, 6, 6, 6, 6, 6,
7726 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7727 7, 7, 7, 7, 7, 7,
7728 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7729 8, 8, 8, 8, 8,
7730 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7731 9, 9, 9, 9, 9, 9,
7732 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7733 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7734 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7735 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7736
7737 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7738 0, 0, 0, 0, 0, 0,
7739 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7740 1, 1, 1,
7741 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7742 2, 2, 2, 2, 2, 2,
7743 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7744 3, 3, 3, 3, 3,
7745 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7746 4, 4, 4, 4, 4, 4,
7747 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7748 5, 5, 5, 5, 5,
7749 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7750 6, 6, 6, 6, 6, 6,
7751 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7752 7, 7, 7, 7, 7, 7,
7753 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7754 8, 8, 8, 8, 8,
7755 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7756 9, 9, 9, 9, 9, 9,
7757 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7758 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7759 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7760 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7761
7762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7763 0, 0, 0, 0, 0, 0,
7764 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7765 1, 1, 1, 1,
7766 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7767 2, 2, 2, 2, 2, 2,
7768 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7769 3, 3, 3, 3, 3,
7770 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7771 4, 4, 4, 4, 4, 4,
7772 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7773 5, 5, 5, 5, 5,
7774 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7775 6, 6, 6, 6, 6, 6,
7776 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7777 7, 7, 7, 7, 7, 7,
7778 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7779 8, 8, 8, 8, 8,
7780 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7781 9, 9, 9, 9, 9, 9,
7782 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7783 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7784 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7785 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7786
7787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7788 0, 0, 0, 0, 0, 0,
7789 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7790 1, 1, 1,
7791 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7792 2, 2, 2, 2, 2, 2,
7793 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7794 3, 3, 3, 3, 3,
7795 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7796 4, 4, 4, 4, 4, 4,
7797 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7798 5, 5, 5, 5, 5,
7799 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7800 6, 6, 6, 6, 6, 6,
7801 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7802 7, 7, 7, 7, 7, 7,
7803 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7804 8, 8, 8, 8, 8,
7805 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7806 9, 9, 9, 9, 9, 9,
7807 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7808 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7809 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7810 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7811
7812
7813// This function works for dates from 1970 to 2099.
7814static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007815 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007816#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007817 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007818#endif
7819
7820 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7821 date %= kDaysIn4Years;
7822
7823 month = kMonthInYear[date];
7824 day = kDayInYear[date];
7825
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007826 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007827}
7828
7829
7830static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007831 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007832#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007833 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007834#endif
7835
7836 date += kDaysOffset;
7837 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7838 date %= kDaysIn400Years;
7839
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007840 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007841
7842 date--;
7843 int yd1 = date / kDaysIn100Years;
7844 date %= kDaysIn100Years;
7845 year += 100 * yd1;
7846
7847 date++;
7848 int yd2 = date / kDaysIn4Years;
7849 date %= kDaysIn4Years;
7850 year += 4 * yd2;
7851
7852 date--;
7853 int yd3 = date / 365;
7854 date %= 365;
7855 year += yd3;
7856
7857 bool is_leap = (!yd1 || yd2) && !yd3;
7858
7859 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007860 ASSERT(is_leap || (date >= 0));
7861 ASSERT((date < 365) || (is_leap && (date < 366)));
7862 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007863 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7864 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007865
7866 if (is_leap) {
7867 day = kDayInYear[2*365 + 1 + date];
7868 month = kMonthInYear[2*365 + 1 + date];
7869 } else {
7870 day = kDayInYear[date];
7871 month = kMonthInYear[date];
7872 }
7873
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007874 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007875}
7876
7877
7878static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007879 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007880 if (date >= 0 && date < 32 * kDaysIn4Years) {
7881 DateYMDFromTimeAfter1970(date, year, month, day);
7882 } else {
7883 DateYMDFromTimeSlow(date, year, month, day);
7884 }
7885}
7886
7887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007888RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007889 NoHandleAllocation ha;
7890 ASSERT(args.length() == 2);
7891
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007892 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007893 CONVERT_ARG_CHECKED(JSArray, res_array, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007894
7895 int year, month, day;
7896 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7897
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007898 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7899 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007900 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007901
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007902 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7903 if (maybe->IsFailure()) return maybe;
7904 FixedArray* elms = FixedArray::cast(res_array->elements());
7905 elms->set(0, Smi::FromInt(year));
7906 elms->set(1, Smi::FromInt(month));
7907 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007908
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007909 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007910}
7911
7912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007913RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007914 HandleScope scope(isolate);
7915 ASSERT(args.length() == 3);
7916
7917 Handle<JSFunction> callee = args.at<JSFunction>(0);
7918 Object** parameters = reinterpret_cast<Object**>(args[1]);
7919 const int argument_count = Smi::cast(args[2])->value();
7920
7921 Handle<JSObject> result =
7922 isolate->factory()->NewArgumentsObject(callee, argument_count);
7923 // Allocate the elements if needed.
7924 int parameter_count = callee->shared()->formal_parameter_count();
7925 if (argument_count > 0) {
7926 if (parameter_count > 0) {
7927 int mapped_count = Min(argument_count, parameter_count);
7928 Handle<FixedArray> parameter_map =
7929 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7930 parameter_map->set_map(
7931 isolate->heap()->non_strict_arguments_elements_map());
7932
7933 Handle<Map> old_map(result->map());
7934 Handle<Map> new_map =
7935 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007936 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007937
7938 result->set_map(*new_map);
7939 result->set_elements(*parameter_map);
7940
7941 // Store the context and the arguments array at the beginning of the
7942 // parameter map.
7943 Handle<Context> context(isolate->context());
7944 Handle<FixedArray> arguments =
7945 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7946 parameter_map->set(0, *context);
7947 parameter_map->set(1, *arguments);
7948
7949 // Loop over the actual parameters backwards.
7950 int index = argument_count - 1;
7951 while (index >= mapped_count) {
7952 // These go directly in the arguments array and have no
7953 // corresponding slot in the parameter map.
7954 arguments->set(index, *(parameters - index - 1));
7955 --index;
7956 }
7957
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007958 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007959 while (index >= 0) {
7960 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007961 Handle<String> name(scope_info->ParameterName(index));
7962 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007963 bool duplicate = false;
7964 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007965 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007966 duplicate = true;
7967 break;
7968 }
7969 }
7970
7971 if (duplicate) {
7972 // This goes directly in the arguments array with a hole in the
7973 // parameter map.
7974 arguments->set(index, *(parameters - index - 1));
7975 parameter_map->set_the_hole(index + 2);
7976 } else {
7977 // The context index goes in the parameter map with a hole in the
7978 // arguments array.
7979 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007980 for (int j = 0; j < context_local_count; ++j) {
7981 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007982 context_index = j;
7983 break;
7984 }
7985 }
7986 ASSERT(context_index >= 0);
7987 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007988 parameter_map->set(index + 2, Smi::FromInt(
7989 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007990 }
7991
7992 --index;
7993 }
7994 } else {
7995 // If there is no aliasing, the arguments object elements are not
7996 // special in any way.
7997 Handle<FixedArray> elements =
7998 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7999 result->set_elements(*elements);
8000 for (int i = 0; i < argument_count; ++i) {
8001 elements->set(i, *(parameters - i - 1));
8002 }
8003 }
8004 }
8005 return *result;
8006}
8007
8008
8009RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008010 NoHandleAllocation ha;
8011 ASSERT(args.length() == 3);
8012
8013 JSFunction* callee = JSFunction::cast(args[0]);
8014 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008015 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008016
lrn@chromium.org303ada72010-10-27 09:33:13 +00008017 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008018 { MaybeObject* maybe_result =
8019 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008020 if (!maybe_result->ToObject(&result)) return maybe_result;
8021 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008022 // Allocate the elements if needed.
8023 if (length > 0) {
8024 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008025 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008026 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008027 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8028 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008029
8030 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008031 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008032 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008033 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008034
8035 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008036 for (int i = 0; i < length; i++) {
8037 array->set(i, *--parameters, mode);
8038 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008039 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008040 }
8041 return result;
8042}
8043
8044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008045RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008046 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008047 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008048 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8049 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8050 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008051
whesse@chromium.org7b260152011-06-20 15:33:18 +00008052 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008053 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008054 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008055 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008056 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8057 context,
8058 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059 return *result;
8060}
8061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008062
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008063// Find the arguments of the JavaScript function invocation that called
8064// into C++ code. Collect these in a newly allocated array of handles (possibly
8065// prefixed by a number of empty handles).
8066static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8067 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008068 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008069 // Find frame containing arguments passed to the caller.
8070 JavaScriptFrameIterator it;
8071 JavaScriptFrame* frame = it.frame();
8072 List<JSFunction*> functions(2);
8073 frame->GetFunctions(&functions);
8074 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008075 int inlined_jsframe_index = functions.length() - 1;
8076 JSFunction* inlined_function = functions[inlined_jsframe_index];
8077 Vector<SlotRef> args_slots =
8078 SlotRef::ComputeSlotMappingForArguments(
8079 frame,
8080 inlined_jsframe_index,
8081 inlined_function->shared()->formal_parameter_count());
8082
8083 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008084
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008085 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008086 SmartArrayPointer<Handle<Object> > param_data(
8087 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008088 for (int i = 0; i < args_count; i++) {
8089 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008090 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008091 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008092
8093 args_slots.Dispose();
8094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008095 return param_data;
8096 } else {
8097 it.AdvanceToArgumentsFrame();
8098 frame = it.frame();
8099 int args_count = frame->ComputeParametersCount();
8100
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008101 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008102 SmartArrayPointer<Handle<Object> > param_data(
8103 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008104 for (int i = 0; i < args_count; i++) {
8105 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008106 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008107 }
8108 return param_data;
8109 }
8110}
8111
8112
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008113RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8114 HandleScope scope(isolate);
8115 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008116 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008117 RUNTIME_ASSERT(args[3]->IsNumber());
8118 Handle<Object> bindee = args.at<Object>(1);
8119
8120 // TODO(lrn): Create bound function in C++ code from premade shared info.
8121 bound_function->shared()->set_bound(true);
8122 // Get all arguments of calling function (Function.prototype.bind).
8123 int argc = 0;
8124 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8125 // Don't count the this-arg.
8126 if (argc > 0) {
8127 ASSERT(*arguments[0] == args[2]);
8128 argc--;
8129 } else {
8130 ASSERT(args[2]->IsUndefined());
8131 }
8132 // Initialize array of bindings (function, this, and any existing arguments
8133 // if the function was already bound).
8134 Handle<FixedArray> new_bindings;
8135 int i;
8136 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8137 Handle<FixedArray> old_bindings(
8138 JSFunction::cast(*bindee)->function_bindings());
8139 new_bindings =
8140 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8141 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8142 i = 0;
8143 for (int n = old_bindings->length(); i < n; i++) {
8144 new_bindings->set(i, old_bindings->get(i));
8145 }
8146 } else {
8147 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8148 new_bindings = isolate->factory()->NewFixedArray(array_size);
8149 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8150 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8151 i = 2;
8152 }
8153 // Copy arguments, skipping the first which is "this_arg".
8154 for (int j = 0; j < argc; j++, i++) {
8155 new_bindings->set(i, *arguments[j + 1]);
8156 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008157 new_bindings->set_map_no_write_barrier(
8158 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008159 bound_function->set_function_bindings(*new_bindings);
8160
8161 // Update length.
8162 Handle<String> length_symbol = isolate->factory()->length_symbol();
8163 Handle<Object> new_length(args.at<Object>(3));
8164 PropertyAttributes attr =
8165 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8166 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8167 return *bound_function;
8168}
8169
8170
8171RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8172 HandleScope handles(isolate);
8173 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008174 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008175 if (callable->IsJSFunction()) {
8176 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8177 if (function->shared()->bound()) {
8178 Handle<FixedArray> bindings(function->function_bindings());
8179 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8180 return *isolate->factory()->NewJSArrayWithElements(bindings);
8181 }
8182 }
8183 return isolate->heap()->undefined_value();
8184}
8185
8186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008187RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008188 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008189 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008190 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008191 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008192 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008193
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008194 // The argument is a bound function. Extract its bound arguments
8195 // and callable.
8196 Handle<FixedArray> bound_args =
8197 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8198 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8199 Handle<Object> bound_function(
8200 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8201 ASSERT(!bound_function->IsJSFunction() ||
8202 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008204 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008205 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008206 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008207 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008208 param_data[i] = Handle<Object>(bound_args->get(
8209 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008210 }
8211
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008212 if (!bound_function->IsJSFunction()) {
8213 bool exception_thrown;
8214 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8215 &exception_thrown);
8216 if (exception_thrown) return Failure::Exception();
8217 }
8218 ASSERT(bound_function->IsJSFunction());
8219
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008220 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008221 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008222 Execution::New(Handle<JSFunction>::cast(bound_function),
8223 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008224 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008225 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008226 }
8227 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008228 return *result;
8229}
8230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008232static void TrySettingInlineConstructStub(Isolate* isolate,
8233 Handle<JSFunction> function) {
8234 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008235 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008236 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008237 }
8238 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008239 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008240 Handle<Code> code = compiler.CompileConstructStub(function);
8241 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008242 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008243}
8244
8245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008246RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008247 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008248 ASSERT(args.length() == 1);
8249
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008250 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008252 // If the constructor isn't a proper function we throw a type error.
8253 if (!constructor->IsJSFunction()) {
8254 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8255 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008256 isolate->factory()->NewTypeError("not_constructor", arguments);
8257 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008258 }
8259
8260 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008261
8262 // If function should not have prototype, construction is not allowed. In this
8263 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008264 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008265 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8266 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008267 isolate->factory()->NewTypeError("not_constructor", arguments);
8268 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008269 }
8270
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008271#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008272 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008273 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274 if (debug->StepInActive()) {
8275 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008276 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008277#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008279 if (function->has_initial_map()) {
8280 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281 // The 'Function' function ignores the receiver object when
8282 // called using 'new' and creates a new JSFunction object that
8283 // is returned. The receiver object is only used for error
8284 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008286 // allocate JSFunctions since it does not properly initialize
8287 // the shared part of the function. Since the receiver is
8288 // ignored anyway, we use the global object as the receiver
8289 // instead of a new JSFunction object. This way, errors are
8290 // reported the same way whether or not 'Function' is called
8291 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008292 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008294 }
8295
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008296 // The function should be compiled for the optimization hints to be
8297 // available. We cannot use EnsureCompiled because that forces a
8298 // compilation through the shared function info which makes it
8299 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008300 if (!function->is_compiled()) {
8301 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8302 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008303
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008304 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008305 if (!function->has_initial_map() &&
8306 shared->IsInobjectSlackTrackingInProgress()) {
8307 // The tracking is already in progress for another function. We can only
8308 // track one initial_map at a time, so we force the completion before the
8309 // function is called as a constructor for the first time.
8310 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008311 }
8312
8313 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008314 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8315 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008316 // Delay setting the stub if inobject slack tracking is in progress.
8317 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008318 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008319 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008321 isolate->counters()->constructed_objects()->Increment();
8322 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008323
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008324 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008325}
8326
8327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008328RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008329 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008330 ASSERT(args.length() == 1);
8331
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008332 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008333 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008334 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008336 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008337}
8338
8339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008340RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008341 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342 ASSERT(args.length() == 1);
8343
8344 Handle<JSFunction> function = args.at<JSFunction>(0);
8345#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008346 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008347 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008349 PrintF("]\n");
8350 }
8351#endif
8352
lrn@chromium.org34e60782011-09-15 07:25:40 +00008353 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008355 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008356 return Failure::Exception();
8357 }
8358
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008359 // All done. Return the compiled code.
8360 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361 return function->code();
8362}
8363
8364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008365RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008366 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008367 ASSERT(args.length() == 1);
8368 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008369
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008370 function->shared()->set_profiler_ticks(0);
8371
lrn@chromium.org34e60782011-09-15 07:25:40 +00008372 // If the function is not compiled ignore the lazy
8373 // recompilation. This can happen if the debugger is activated and
8374 // the function is returned to the not compiled state.
8375 if (!function->shared()->is_compiled()) {
8376 function->ReplaceCode(function->shared()->code());
8377 return function->code();
8378 }
8379
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008380 // If the function is not optimizable or debugger is active continue using the
8381 // code from the full compiler.
8382 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008383 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008384 if (FLAG_trace_opt) {
8385 PrintF("[failed to optimize ");
8386 function->PrintName();
8387 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8388 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008389 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008390 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008391 function->ReplaceCode(function->shared()->code());
8392 return function->code();
8393 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008394 if (JSFunction::CompileOptimized(function,
8395 AstNode::kNoNumber,
8396 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008397 return function->code();
8398 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008399 if (FLAG_trace_opt) {
8400 PrintF("[failed to optimize ");
8401 function->PrintName();
8402 PrintF(": optimized compilation failed]\n");
8403 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008404 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008405 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008406}
8407
8408
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008409class ActivationsFinder : public ThreadVisitor {
8410 public:
8411 explicit ActivationsFinder(JSFunction* function)
8412 : function_(function), has_activations_(false) {}
8413
8414 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8415 if (has_activations_) return;
8416
8417 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8418 JavaScriptFrame* frame = it.frame();
8419 if (frame->is_optimized() && frame->function() == function_) {
8420 has_activations_ = true;
8421 return;
8422 }
8423 }
8424 }
8425
8426 bool has_activations() { return has_activations_; }
8427
8428 private:
8429 JSFunction* function_;
8430 bool has_activations_;
8431};
8432
8433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008434RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008435 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008436 ASSERT(args.length() == 1);
8437 RUNTIME_ASSERT(args[0]->IsSmi());
8438 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008439 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8441 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008442 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008443
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008444 deoptimizer->MaterializeHeapNumbers();
8445 delete deoptimizer;
8446
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008447 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008448 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008449 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008450 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008451
8452 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008454 Handle<Object> arguments;
8455 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008456 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008457 if (arguments.is_null()) {
8458 // FunctionGetArguments can't throw an exception, so cast away the
8459 // doubt with an assert.
8460 arguments = Handle<Object>(
8461 Accessors::FunctionGetArguments(*function,
8462 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008463 ASSERT(*arguments != isolate->heap()->null_value());
8464 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008465 }
8466 frame->SetExpression(i, *arguments);
8467 }
8468 }
8469
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008470 if (type == Deoptimizer::EAGER) {
8471 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008472 }
8473
8474 // Avoid doing too much work when running with --always-opt and keep
8475 // the optimized code around.
8476 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008477 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008478 }
8479
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008480 // Find other optimized activations of the function.
8481 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008482 while (!it.done()) {
8483 JavaScriptFrame* frame = it.frame();
8484 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008485 has_other_activations = true;
8486 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008487 }
8488 it.Advance();
8489 }
8490
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008491 if (!has_other_activations) {
8492 ActivationsFinder activations_finder(*function);
8493 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8494 has_other_activations = activations_finder.has_activations();
8495 }
8496
8497 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008498 if (FLAG_trace_deopt) {
8499 PrintF("[removing optimized code for: ");
8500 function->PrintName();
8501 PrintF("]\n");
8502 }
8503 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008504 } else {
8505 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008506 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008507 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008508}
8509
8510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008511RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008512 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008513 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008514 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008515}
8516
8517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008518RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008519 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008520 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008521 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008523
8524 Deoptimizer::DeoptimizeFunction(*function);
8525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008526 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008527}
8528
8529
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008530RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8531#if defined(USE_SIMULATOR)
8532 return isolate->heap()->true_value();
8533#else
8534 return isolate->heap()->false_value();
8535#endif
8536}
8537
8538
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008539RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8540 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008541 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008542 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008543
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008544 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8545 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008546
8547 Code* unoptimized = function->shared()->code();
8548 if (args.length() == 2 &&
8549 unoptimized->kind() == Code::FUNCTION) {
8550 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8551 CHECK(type->IsEqualTo(CStrVector("osr")));
8552 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8553 unoptimized->set_allow_osr_at_loop_nesting_level(
8554 Code::kMaxLoopNestingMarker);
8555 }
8556
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008557 return isolate->heap()->undefined_value();
8558}
8559
8560
lrn@chromium.org1c092762011-05-09 09:42:16 +00008561RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8562 HandleScope scope(isolate);
8563 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008564 // The least significant bit (after untagging) indicates whether the
8565 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008566 if (!V8::UseCrankshaft()) {
8567 return Smi::FromInt(4); // 4 == "never".
8568 }
8569 if (FLAG_always_opt) {
8570 return Smi::FromInt(3); // 3 == "always".
8571 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008572 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008573 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8574 : Smi::FromInt(2); // 2 == "no".
8575}
8576
8577
8578RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8579 HandleScope scope(isolate);
8580 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008581 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008582 return Smi::FromInt(function->shared()->opt_count());
8583}
8584
8585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008586RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008587 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008588 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008589 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008590
8591 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008592 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008593
8594 // We have hit a back edge in an unoptimized frame for a function that was
8595 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008596 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008597 // Keep track of whether we've succeeded in optimizing.
8598 bool succeeded = unoptimized->optimizable();
8599 if (succeeded) {
8600 // If we are trying to do OSR when there are already optimized
8601 // activations of the function, it means (a) the function is directly or
8602 // indirectly recursive and (b) an optimized invocation has been
8603 // deoptimized so that we are currently in an unoptimized activation.
8604 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008605 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008606 while (succeeded && !it.done()) {
8607 JavaScriptFrame* frame = it.frame();
8608 succeeded = !frame->is_optimized() || frame->function() != *function;
8609 it.Advance();
8610 }
8611 }
8612
8613 int ast_id = AstNode::kNoNumber;
8614 if (succeeded) {
8615 // The top JS function is this one, the PC is somewhere in the
8616 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008617 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008618 JavaScriptFrame* frame = it.frame();
8619 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008620 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008621 ASSERT(unoptimized->contains(frame->pc()));
8622
8623 // Use linear search of the unoptimized code's stack check table to find
8624 // the AST id matching the PC.
8625 Address start = unoptimized->instruction_start();
8626 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008627 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008628 uint32_t table_length = Memory::uint32_at(table_cursor);
8629 table_cursor += kIntSize;
8630 for (unsigned i = 0; i < table_length; ++i) {
8631 // Table entries are (AST id, pc offset) pairs.
8632 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8633 if (pc_offset == target_pc_offset) {
8634 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8635 break;
8636 }
8637 table_cursor += 2 * kIntSize;
8638 }
8639 ASSERT(ast_id != AstNode::kNoNumber);
8640 if (FLAG_trace_osr) {
8641 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8642 function->PrintName();
8643 PrintF("]\n");
8644 }
8645
8646 // Try to compile the optimized code. A true return value from
8647 // CompileOptimized means that compilation succeeded, not necessarily
8648 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008649 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008650 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008651 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8652 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008653 if (data->OsrPcOffset()->value() >= 0) {
8654 if (FLAG_trace_osr) {
8655 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008656 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008657 }
8658 ASSERT(data->OsrAstId()->value() == ast_id);
8659 } else {
8660 // We may never generate the desired OSR entry if we emit an
8661 // early deoptimize.
8662 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008663 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008664 } else {
8665 succeeded = false;
8666 }
8667 }
8668
8669 // Revert to the original stack checks in the original unoptimized code.
8670 if (FLAG_trace_osr) {
8671 PrintF("[restoring original stack checks in ");
8672 function->PrintName();
8673 PrintF("]\n");
8674 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008675 Handle<Code> check_code;
8676#ifdef V8_TARGET_ARCH_IA32
8677 if (FLAG_count_based_interrupts) {
8678 InterruptStub interrupt_stub;
8679 check_code = interrupt_stub.GetCode();
8680 } else // NOLINT
8681#endif
8682 { // NOLINT
8683 StackCheckStub check_stub;
8684 check_code = check_stub.GetCode();
8685 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008686 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008687 Deoptimizer::RevertStackCheckCode(*unoptimized,
8688 *check_code,
8689 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008690
8691 // Allow OSR only at nesting level zero again.
8692 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8693
8694 // If the optimization attempt succeeded, return the AST id tagged as a
8695 // smi. This tells the builtin that we need to translate the unoptimized
8696 // frame to an optimized one.
8697 if (succeeded) {
8698 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8699 return Smi::FromInt(ast_id);
8700 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008701 if (function->IsMarkedForLazyRecompilation()) {
8702 function->ReplaceCode(function->shared()->code());
8703 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008704 return Smi::FromInt(-1);
8705 }
8706}
8707
8708
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008709RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8710 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8711 return isolate->heap()->undefined_value();
8712}
8713
8714
danno@chromium.orgc612e022011-11-10 11:38:15 +00008715RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8716 HandleScope scope(isolate);
8717 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008718 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008719 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8720 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008721
8722 // If there are too many arguments, allocate argv via malloc.
8723 const int argv_small_size = 10;
8724 Handle<Object> argv_small_buffer[argv_small_size];
8725 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8726 Handle<Object>* argv = argv_small_buffer;
8727 if (argc > argv_small_size) {
8728 argv = new Handle<Object>[argc];
8729 if (argv == NULL) return isolate->StackOverflow();
8730 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8731 }
8732
8733 for (int i = 0; i < argc; ++i) {
8734 MaybeObject* maybe = args[1 + i];
8735 Object* object;
8736 if (!maybe->To<Object>(&object)) return maybe;
8737 argv[i] = Handle<Object>(object);
8738 }
8739
8740 bool threw;
8741 Handle<JSReceiver> hfun(fun);
8742 Handle<Object> hreceiver(receiver);
8743 Handle<Object> result =
8744 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8745
8746 if (threw) return Failure::Exception();
8747 return *result;
8748}
8749
8750
lrn@chromium.org34e60782011-09-15 07:25:40 +00008751RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8752 HandleScope scope(isolate);
8753 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008754 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008755 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008756 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008757 CONVERT_SMI_ARG_CHECKED(offset, 3);
8758 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008759 ASSERT(offset >= 0);
8760 ASSERT(argc >= 0);
8761
8762 // If there are too many arguments, allocate argv via malloc.
8763 const int argv_small_size = 10;
8764 Handle<Object> argv_small_buffer[argv_small_size];
8765 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8766 Handle<Object>* argv = argv_small_buffer;
8767 if (argc > argv_small_size) {
8768 argv = new Handle<Object>[argc];
8769 if (argv == NULL) return isolate->StackOverflow();
8770 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8771 }
8772
8773 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008774 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008775 }
8776
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008777 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008778 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008779 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008780
8781 if (threw) return Failure::Exception();
8782 return *result;
8783}
8784
8785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008787 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008788 ASSERT(args.length() == 1);
8789 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8790 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8791}
8792
8793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008794RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008796 ASSERT(args.length() == 1);
8797 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8798 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8799}
8800
8801
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008802RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008804 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008805
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008806 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008807 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008808 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 { MaybeObject* maybe_result =
8810 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008811 if (!maybe_result->ToObject(&result)) return maybe_result;
8812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008813
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008814 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815
kasper.lund7276f142008-07-30 08:49:36 +00008816 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008817}
8818
lrn@chromium.org303ada72010-10-27 09:33:13 +00008819
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8821 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008822 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008823 JSObject* extension_object;
8824 if (args[0]->IsJSObject()) {
8825 extension_object = JSObject::cast(args[0]);
8826 } else {
8827 // Convert the object to a proper JavaScript object.
8828 MaybeObject* maybe_js_object = args[0]->ToObject();
8829 if (!maybe_js_object->To(&extension_object)) {
8830 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8831 HandleScope scope(isolate);
8832 Handle<Object> handle = args.at<Object>(0);
8833 Handle<Object> result =
8834 isolate->factory()->NewTypeError("with_expression",
8835 HandleVector(&handle, 1));
8836 return isolate->Throw(*result);
8837 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008838 return maybe_js_object;
8839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008840 }
8841 }
8842
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008843 JSFunction* function;
8844 if (args[1]->IsSmi()) {
8845 // A smi sentinel indicates a context nested inside global code rather
8846 // than some function. There is a canonical empty function that can be
8847 // gotten from the global context.
8848 function = isolate->context()->global_context()->closure();
8849 } else {
8850 function = JSFunction::cast(args[1]);
8851 }
8852
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008853 Context* context;
8854 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008855 isolate->heap()->AllocateWithContext(function,
8856 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008857 extension_object);
8858 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008859 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008860 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008861}
8862
8863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008864RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008865 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008866 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008867 String* name = String::cast(args[0]);
8868 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008869 JSFunction* function;
8870 if (args[2]->IsSmi()) {
8871 // A smi sentinel indicates a context nested inside global code rather
8872 // than some function. There is a canonical empty function that can be
8873 // gotten from the global context.
8874 function = isolate->context()->global_context()->closure();
8875 } else {
8876 function = JSFunction::cast(args[2]);
8877 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008878 Context* context;
8879 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008880 isolate->heap()->AllocateCatchContext(function,
8881 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008882 name,
8883 thrown_object);
8884 if (!maybe_context->To(&context)) return maybe_context;
8885 isolate->set_context(context);
8886 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008887}
8888
8889
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8891 NoHandleAllocation ha;
8892 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008893 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008894 JSFunction* function;
8895 if (args[1]->IsSmi()) {
8896 // A smi sentinel indicates a context nested inside global code rather
8897 // than some function. There is a canonical empty function that can be
8898 // gotten from the global context.
8899 function = isolate->context()->global_context()->closure();
8900 } else {
8901 function = JSFunction::cast(args[1]);
8902 }
8903 Context* context;
8904 MaybeObject* maybe_context =
8905 isolate->heap()->AllocateBlockContext(function,
8906 isolate->context(),
8907 scope_info);
8908 if (!maybe_context->To(&context)) return maybe_context;
8909 isolate->set_context(context);
8910 return context;
8911}
8912
8913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008914RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008915 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008916 ASSERT(args.length() == 2);
8917
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008918 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8919 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008920
8921 int index;
8922 PropertyAttributes attributes;
8923 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008924 BindingFlags binding_flags;
8925 Handle<Object> holder = context->Lookup(name,
8926 flags,
8927 &index,
8928 &attributes,
8929 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008931 // If the slot was not found the result is true.
8932 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008933 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934 }
8935
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008936 // If the slot was found in a context, it should be DONT_DELETE.
8937 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008938 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008939 }
8940
8941 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008942 // the global object, or the subject of a with. Try to delete it
8943 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008944 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008945 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946}
8947
8948
ager@chromium.orga1645e22009-09-09 19:27:10 +00008949// A mechanism to return a pair of Object pointers in registers (if possible).
8950// How this is achieved is calling convention-dependent.
8951// All currently supported x86 compiles uses calling conventions that are cdecl
8952// variants where a 64-bit value is returned in two 32-bit registers
8953// (edx:eax on ia32, r1:r0 on ARM).
8954// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8955// In Win64 calling convention, a struct of two pointers is returned in memory,
8956// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008957#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008958struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008959 MaybeObject* x;
8960 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008961};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008962
lrn@chromium.org303ada72010-10-27 09:33:13 +00008963static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008964 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008965 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8966 // In Win64 they are assigned to a hidden first argument.
8967 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008968}
8969#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008970typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008971static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008973 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008975#endif
8976
8977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008978static inline MaybeObject* Unhole(Heap* heap,
8979 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008980 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8982 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008983 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008984}
8985
8986
danno@chromium.org40cb8782011-05-25 07:58:50 +00008987static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8988 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008989 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008990 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008991 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008992 JSFunction* context_extension_function =
8993 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008994 // If the holder isn't a context extension object, we just return it
8995 // as the receiver. This allows arguments objects to be used as
8996 // receivers, but only if they are put in the context scope chain
8997 // explicitly via a with-statement.
8998 Object* constructor = holder->map()->constructor();
8999 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009000 // Fall back to using the global object as the implicit receiver if
9001 // the property turns out to be a local variable allocated in a
9002 // context extension object - introduced via eval. Implicit global
9003 // receivers are indicated with the hole value.
9004 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009005}
9006
9007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008static ObjectPair LoadContextSlotHelper(Arguments args,
9009 Isolate* isolate,
9010 bool throw_error) {
9011 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009012 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009014 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009018 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019
9020 int index;
9021 PropertyAttributes attributes;
9022 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009023 BindingFlags binding_flags;
9024 Handle<Object> holder = context->Lookup(name,
9025 flags,
9026 &index,
9027 &attributes,
9028 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009030 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009032 ASSERT(holder->IsContext());
9033 // If the "property" we were looking for is a local variable, the
9034 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009035 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009036 // Use the hole as the receiver to signal that the receiver is implicit
9037 // and that the global receiver should be used (as distinguished from an
9038 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009039 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009040 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009041 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009042 switch (binding_flags) {
9043 case MUTABLE_CHECK_INITIALIZED:
9044 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9045 if (value->IsTheHole()) {
9046 Handle<Object> reference_error =
9047 isolate->factory()->NewReferenceError("not_defined",
9048 HandleVector(&name, 1));
9049 return MakePair(isolate->Throw(*reference_error), NULL);
9050 }
9051 // FALLTHROUGH
9052 case MUTABLE_IS_INITIALIZED:
9053 case IMMUTABLE_IS_INITIALIZED:
9054 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9055 ASSERT(!value->IsTheHole());
9056 return MakePair(value, *receiver);
9057 case IMMUTABLE_CHECK_INITIALIZED:
9058 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9059 case MISSING_BINDING:
9060 UNREACHABLE();
9061 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009063 }
9064
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009065 // Otherwise, if the slot was found the holder is a context extension
9066 // object, subject of a with, or a global object. We read the named
9067 // property from it.
9068 if (!holder.is_null()) {
9069 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9070 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009071 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009072 Handle<Object> receiver_handle(object->IsGlobalObject()
9073 ? GlobalObject::cast(*object)->global_receiver()
9074 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009075
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009076 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009077 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009078 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009079 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009080 }
9081
9082 if (throw_error) {
9083 // The property doesn't exist - throw exception.
9084 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009085 isolate->factory()->NewReferenceError("not_defined",
9086 HandleVector(&name, 1));
9087 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009088 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009089 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009090 return MakePair(isolate->heap()->undefined_value(),
9091 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092 }
9093}
9094
9095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009096RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098}
9099
9100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009101RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009102 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009103}
9104
9105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009106RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009108 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009110 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009111 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9112 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009113 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9114 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9115 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009116
9117 int index;
9118 PropertyAttributes attributes;
9119 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009120 BindingFlags binding_flags;
9121 Handle<Object> holder = context->Lookup(name,
9122 flags,
9123 &index,
9124 &attributes,
9125 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009126
9127 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009128 // The property was found in a context slot.
9129 Handle<Context> context = Handle<Context>::cast(holder);
9130 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9131 context->get(index)->IsTheHole()) {
9132 Handle<Object> error =
9133 isolate->factory()->NewReferenceError("not_defined",
9134 HandleVector(&name, 1));
9135 return isolate->Throw(*error);
9136 }
9137 // Ignore if read_only variable.
9138 if ((attributes & READ_ONLY) == 0) {
9139 // Context is a fixed array and set cannot fail.
9140 context->set(index, *value);
9141 } else if (strict_mode == kStrictMode) {
9142 // Setting read only property in strict mode.
9143 Handle<Object> error =
9144 isolate->factory()->NewTypeError("strict_cannot_assign",
9145 HandleVector(&name, 1));
9146 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147 }
9148 return *value;
9149 }
9150
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009151 // Slow case: The property is not in a context slot. It is either in a
9152 // context extension object, a property of the subject of a with, or a
9153 // property of the global object.
9154 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009156 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009157 // The property exists on the holder.
9158 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009160 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009162
9163 if (strict_mode == kStrictMode) {
9164 // Throw in strict mode (assignment to undefined variable).
9165 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009166 isolate->factory()->NewReferenceError(
9167 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009168 return isolate->Throw(*error);
9169 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009170 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009172 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173 }
9174
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009175 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009176 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009177 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009178 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009180 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009181 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009182 // Setting read only property in strict mode.
9183 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 isolate->factory()->NewTypeError(
9185 "strict_cannot_assign", HandleVector(&name, 1));
9186 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 }
9188 return *value;
9189}
9190
9191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009192RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009193 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009194 ASSERT(args.length() == 1);
9195
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197}
9198
9199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009200RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009201 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 ASSERT(args.length() == 1);
9203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009204 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009205}
9206
9207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009208RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009209 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009211}
9212
9213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009214RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216 ASSERT(args.length() == 1);
9217
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009218 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009219 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009220 isolate->factory()->NewReferenceError("not_defined",
9221 HandleVector(&name, 1));
9222 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223}
9224
9225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009226RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009227 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228
9229 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 if (isolate->stack_guard()->IsStackOverflow()) {
9231 NoHandleAllocation na;
9232 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009233 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234
ulan@chromium.org812308e2012-02-29 15:58:45 +00009235 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236}
9237
9238
yangguo@chromium.org56454712012-02-16 15:33:53 +00009239RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9240 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00009241 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009242}
9243
9244
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245static int StackSize() {
9246 int n = 0;
9247 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9248 return n;
9249}
9250
9251
9252static void PrintTransition(Object* result) {
9253 // indentation
9254 { const int nmax = 80;
9255 int n = StackSize();
9256 if (n <= nmax)
9257 PrintF("%4d:%*s", n, n, "");
9258 else
9259 PrintF("%4d:%*s", n, nmax, "...");
9260 }
9261
9262 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009263 JavaScriptFrame::PrintTop(stdout, true, false);
9264 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265 } else {
9266 // function result
9267 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009268 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009269 PrintF("\n");
9270 }
9271}
9272
9273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009274RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009275 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276 NoHandleAllocation ha;
9277 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009278 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279}
9280
9281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283 NoHandleAllocation ha;
9284 PrintTransition(args[0]);
9285 return args[0]; // return TOS
9286}
9287
9288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009289RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290 NoHandleAllocation ha;
9291 ASSERT(args.length() == 1);
9292
9293#ifdef DEBUG
9294 if (args[0]->IsString()) {
9295 // If we have a string, assume it's a code "marker"
9296 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009297 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009299 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9300 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301 } else {
9302 PrintF("DebugPrint: ");
9303 }
9304 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009305 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009306 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009307 HeapObject::cast(args[0])->map()->Print();
9308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009310 // ShortPrint is available in release mode. Print is not.
9311 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312#endif
9313 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009314 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315
9316 return args[0]; // return TOS
9317}
9318
9319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009320RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009321 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 isolate->PrintStack();
9324 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325}
9326
9327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009328RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009330 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009331
9332 // According to ECMA-262, section 15.9.1, page 117, the precision of
9333 // the number in a Date object representing a particular instant in
9334 // time is milliseconds. Therefore, we floor the result of getting
9335 // the OS time.
9336 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009337 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338}
9339
9340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009341RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009342 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009343 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009345 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009346 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009347
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009348 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009349
9350 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009351 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009352 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009353 RUNTIME_ASSERT(output->HasFastElements());
9354
9355 AssertNoAllocation no_allocation;
9356
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009357 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009358 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9359 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009360 String::FlatContent str_content = str->GetFlatContent();
9361 if (str_content.IsAscii()) {
9362 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009363 output_array,
9364 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009365 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009366 ASSERT(str_content.IsTwoByte());
9367 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009368 output_array,
9369 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009370 }
9371
9372 if (result) {
9373 return *output;
9374 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009375 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009376 }
9377}
9378
9379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009380RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009381 NoHandleAllocation ha;
9382 ASSERT(args.length() == 1);
9383
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009384 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009385 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009386 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387}
9388
9389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009390RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009392 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009395}
9396
9397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009398RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399 NoHandleAllocation ha;
9400 ASSERT(args.length() == 1);
9401
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009402 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009403 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009404}
9405
9406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009407RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009408 ASSERT(args.length() == 1);
9409 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009410 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009411 return JSGlobalObject::cast(global)->global_receiver();
9412}
9413
9414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009415RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009416 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009417 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009418 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009419
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009420 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009421 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009422 Handle<Object> result;
9423 if (source->IsSeqAsciiString()) {
9424 result = JsonParser<true>::Parse(source);
9425 } else {
9426 result = JsonParser<false>::Parse(source);
9427 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009428 if (result.is_null()) {
9429 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009430 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009431 return Failure::Exception();
9432 }
9433 return *result;
9434}
9435
9436
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009437bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9438 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009439 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9440 // Check with callback if set.
9441 AllowCodeGenerationFromStringsCallback callback =
9442 isolate->allow_code_gen_callback();
9443 if (callback == NULL) {
9444 // No callback set and code generation disallowed.
9445 return false;
9446 } else {
9447 // Callback set. Let it decide if code generation is allowed.
9448 VMState state(isolate, EXTERNAL);
9449 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009450 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009451}
9452
9453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009454RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009455 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009456 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009457 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009458
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009459 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009460 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009461
9462 // Check if global context allows code generation from
9463 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009464 if (context->allow_code_gen_from_strings()->IsFalse() &&
9465 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009466 return isolate->Throw(*isolate->factory()->NewError(
9467 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9468 }
9469
9470 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009471 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009472 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009473 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009474 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9476 context,
9477 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009478 return *fun;
9479}
9480
9481
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482static ObjectPair CompileGlobalEval(Isolate* isolate,
9483 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009484 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009485 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009486 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009487 Handle<Context> context = Handle<Context>(isolate->context());
9488 Handle<Context> global_context = Handle<Context>(context->global_context());
9489
9490 // Check if global context allows code generation from
9491 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009492 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9493 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009494 isolate->Throw(*isolate->factory()->NewError(
9495 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9496 return MakePair(Failure::Exception(), NULL);
9497 }
9498
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009499 // Deal with a normal eval call with a string argument. Compile it
9500 // and return the compiled function bound in the local context.
9501 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9502 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009503 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009504 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009505 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009506 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009507 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009508 Handle<JSFunction> compiled =
9509 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009510 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009511 return MakePair(*compiled, *receiver);
9512}
9513
9514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009515RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009516 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009518 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009519 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009520
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009521 // If "eval" didn't refer to the original GlobalEval, it's not a
9522 // direct call to eval.
9523 // (And even if it is, but the first argument isn't a string, just let
9524 // execution default to an indirect call to eval, which will also return
9525 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009527 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009528 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009529 }
9530
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009531 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009532 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009533 return CompileGlobalEval(isolate,
9534 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009535 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009536 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009537 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009538}
9539
9540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009541RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 // This utility adjusts the property attributes for newly created Function
9543 // object ("new Function(...)") by changing the map.
9544 // All it does is changing the prototype property to enumerable
9545 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009546 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009547 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009548 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009550 Handle<Map> map = func->shared()->is_classic_mode()
9551 ? isolate->function_instance_map()
9552 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553
9554 ASSERT(func->map()->instance_type() == map->instance_type());
9555 ASSERT(func->map()->instance_size() == map->instance_size());
9556 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009557 return *func;
9558}
9559
9560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009561RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009562 // Allocate a block of memory in NewSpace (filled with a filler).
9563 // Use as fallback for allocation in generated code when NewSpace
9564 // is full.
9565 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009566 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009567 int size = size_smi->value();
9568 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9569 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 Heap* heap = isolate->heap();
9571 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009572 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009573 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009574 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009575 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009576 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009577 }
9578 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009579 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009580}
9581
9582
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009583// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009584// array. Returns true if the element was pushed on the stack and
9585// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009586RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009587 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009588 CONVERT_ARG_CHECKED(JSArray, array, 0);
9589 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009590 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009591 int length = Smi::cast(array->length())->value();
9592 FixedArray* elements = FixedArray::cast(array->elements());
9593 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009595 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009596 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009597 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009598 { MaybeObject* maybe_obj =
9599 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009600 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009602 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009603}
9604
9605
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009606/**
9607 * A simple visitor visits every element of Array's.
9608 * The backend storage can be a fixed array for fast elements case,
9609 * or a dictionary for sparse array. Since Dictionary is a subtype
9610 * of FixedArray, the class can be used by both fast and slow cases.
9611 * The second parameter of the constructor, fast_elements, specifies
9612 * whether the storage is a FixedArray or Dictionary.
9613 *
9614 * An index limit is used to deal with the situation that a result array
9615 * length overflows 32-bit non-negative integer.
9616 */
9617class ArrayConcatVisitor {
9618 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009619 ArrayConcatVisitor(Isolate* isolate,
9620 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009621 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009622 isolate_(isolate),
9623 storage_(Handle<FixedArray>::cast(
9624 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009625 index_offset_(0u),
9626 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009627
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009628 ~ArrayConcatVisitor() {
9629 clear_storage();
9630 }
9631
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009632 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009634 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009635
9636 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 if (index < static_cast<uint32_t>(storage_->length())) {
9638 storage_->set(index, *elm);
9639 return;
9640 }
9641 // Our initial estimate of length was foiled, possibly by
9642 // getters on the arrays increasing the length of later arrays
9643 // during iteration.
9644 // This shouldn't happen in anything but pathological cases.
9645 SetDictionaryMode(index);
9646 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009647 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009649 Handle<SeededNumberDictionary> dict(
9650 SeededNumberDictionary::cast(*storage_));
9651 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009652 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009653 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009654 // Dictionary needed to grow.
9655 clear_storage();
9656 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 }
9658}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009659
9660 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009661 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9662 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009663 } else {
9664 index_offset_ += delta;
9665 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009666 }
9667
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009669 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009670 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009671 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009672 Handle<Map> map;
9673 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009674 map = isolate_->factory()->GetElementsTransitionMap(array,
9675 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009677 map = isolate_->factory()->GetElementsTransitionMap(array,
9678 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009679 }
9680 array->set_map(*map);
9681 array->set_length(*length);
9682 array->set_elements(*storage_);
9683 return array;
9684 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009685
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009686 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009687 // Convert storage to dictionary mode.
9688 void SetDictionaryMode(uint32_t index) {
9689 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009690 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009691 Handle<SeededNumberDictionary> slow_storage(
9692 isolate_->factory()->NewSeededNumberDictionary(
9693 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009694 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9695 for (uint32_t i = 0; i < current_length; i++) {
9696 HandleScope loop_scope;
9697 Handle<Object> element(current_storage->get(i));
9698 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009699 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009700 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009701 if (!new_storage.is_identical_to(slow_storage)) {
9702 slow_storage = loop_scope.CloseAndEscape(new_storage);
9703 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 }
9705 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009706 clear_storage();
9707 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009708 fast_elements_ = false;
9709 }
9710
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009711 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009712 isolate_->global_handles()->Destroy(
9713 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009714 }
9715
9716 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009717 storage_ = Handle<FixedArray>::cast(
9718 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009719 }
9720
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009721 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009722 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 // Index after last seen index. Always less than or equal to
9724 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009725 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009726 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009727};
9728
9729
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009730static uint32_t EstimateElementCount(Handle<JSArray> array) {
9731 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9732 int element_count = 0;
9733 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009734 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009735 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009736 // Fast elements can't have lengths that are not representable by
9737 // a 32-bit signed integer.
9738 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9739 int fast_length = static_cast<int>(length);
9740 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9741 for (int i = 0; i < fast_length; i++) {
9742 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009743 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009744 break;
9745 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009746 case FAST_DOUBLE_ELEMENTS:
9747 // TODO(1810): Decide if it's worthwhile to implement this.
9748 UNREACHABLE();
9749 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009750 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009751 Handle<SeededNumberDictionary> dictionary(
9752 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009753 int capacity = dictionary->Capacity();
9754 for (int i = 0; i < capacity; i++) {
9755 Handle<Object> key(dictionary->KeyAt(i));
9756 if (dictionary->IsKey(*key)) {
9757 element_count++;
9758 }
9759 }
9760 break;
9761 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009762 case NON_STRICT_ARGUMENTS_ELEMENTS:
9763 case EXTERNAL_BYTE_ELEMENTS:
9764 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9765 case EXTERNAL_SHORT_ELEMENTS:
9766 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9767 case EXTERNAL_INT_ELEMENTS:
9768 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9769 case EXTERNAL_FLOAT_ELEMENTS:
9770 case EXTERNAL_DOUBLE_ELEMENTS:
9771 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009772 // External arrays are always dense.
9773 return length;
9774 }
9775 // As an estimate, we assume that the prototype doesn't contain any
9776 // inherited elements.
9777 return element_count;
9778}
9779
9780
9781
9782template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009783static void IterateExternalArrayElements(Isolate* isolate,
9784 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009785 bool elements_are_ints,
9786 bool elements_are_guaranteed_smis,
9787 ArrayConcatVisitor* visitor) {
9788 Handle<ExternalArrayClass> array(
9789 ExternalArrayClass::cast(receiver->elements()));
9790 uint32_t len = static_cast<uint32_t>(array->length());
9791
9792 ASSERT(visitor != NULL);
9793 if (elements_are_ints) {
9794 if (elements_are_guaranteed_smis) {
9795 for (uint32_t j = 0; j < len; j++) {
9796 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009797 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009798 visitor->visit(j, e);
9799 }
9800 } else {
9801 for (uint32_t j = 0; j < len; j++) {
9802 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009803 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009804 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9805 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9806 visitor->visit(j, e);
9807 } else {
9808 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009809 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009810 visitor->visit(j, e);
9811 }
9812 }
9813 }
9814 } else {
9815 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009816 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009817 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 visitor->visit(j, e);
9819 }
9820 }
9821}
9822
9823
9824// Used for sorting indices in a List<uint32_t>.
9825static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9826 uint32_t a = *ap;
9827 uint32_t b = *bp;
9828 return (a == b) ? 0 : (a < b) ? -1 : 1;
9829}
9830
9831
9832static void CollectElementIndices(Handle<JSObject> object,
9833 uint32_t range,
9834 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009835 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009836 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009837 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009838 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9840 uint32_t length = static_cast<uint32_t>(elements->length());
9841 if (range < length) length = range;
9842 for (uint32_t i = 0; i < length; i++) {
9843 if (!elements->get(i)->IsTheHole()) {
9844 indices->Add(i);
9845 }
9846 }
9847 break;
9848 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009849 case FAST_DOUBLE_ELEMENTS: {
9850 // TODO(1810): Decide if it's worthwhile to implement this.
9851 UNREACHABLE();
9852 break;
9853 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009854 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009855 Handle<SeededNumberDictionary> dict(
9856 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009857 uint32_t capacity = dict->Capacity();
9858 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009860 Handle<Object> k(dict->KeyAt(j));
9861 if (dict->IsKey(*k)) {
9862 ASSERT(k->IsNumber());
9863 uint32_t index = static_cast<uint32_t>(k->Number());
9864 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009865 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009866 }
9867 }
9868 }
9869 break;
9870 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009871 default: {
9872 int dense_elements_length;
9873 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009874 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009875 dense_elements_length =
9876 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009877 break;
9878 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009879 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009880 dense_elements_length =
9881 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009882 break;
9883 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009884 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009885 dense_elements_length =
9886 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009887 break;
9888 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009889 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009890 dense_elements_length =
9891 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009892 break;
9893 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009894 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009895 dense_elements_length =
9896 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009897 break;
9898 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009899 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009900 dense_elements_length =
9901 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009902 break;
9903 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009904 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009905 dense_elements_length =
9906 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009907 break;
9908 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009909 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009910 dense_elements_length =
9911 ExternalFloatArray::cast(object->elements())->length();
9912 break;
9913 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009914 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009915 dense_elements_length =
9916 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 break;
9918 }
9919 default:
9920 UNREACHABLE();
9921 dense_elements_length = 0;
9922 break;
9923 }
9924 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9925 if (range <= length) {
9926 length = range;
9927 // We will add all indices, so we might as well clear it first
9928 // and avoid duplicates.
9929 indices->Clear();
9930 }
9931 for (uint32_t i = 0; i < length; i++) {
9932 indices->Add(i);
9933 }
9934 if (length == range) return; // All indices accounted for already.
9935 break;
9936 }
9937 }
9938
9939 Handle<Object> prototype(object->GetPrototype());
9940 if (prototype->IsJSObject()) {
9941 // The prototype will usually have no inherited element indices,
9942 // but we have to check.
9943 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9944 }
9945}
9946
9947
9948/**
9949 * A helper function that visits elements of a JSArray in numerical
9950 * order.
9951 *
9952 * The visitor argument called for each existing element in the array
9953 * with the element index and the element's value.
9954 * Afterwards it increments the base-index of the visitor by the array
9955 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009956 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009957 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009958static bool IterateElements(Isolate* isolate,
9959 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009960 ArrayConcatVisitor* visitor) {
9961 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9962 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009963 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009964 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009965 // Run through the elements FixedArray and use HasElement and GetElement
9966 // to check the prototype for missing elements.
9967 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9968 int fast_length = static_cast<int>(length);
9969 ASSERT(fast_length <= elements->length());
9970 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009971 HandleScope loop_scope(isolate);
9972 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009973 if (!element_value->IsTheHole()) {
9974 visitor->visit(j, element_value);
9975 } else if (receiver->HasElement(j)) {
9976 // Call GetElement on receiver, not its prototype, or getters won't
9977 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009978 element_value = Object::GetElement(receiver, j);
9979 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009980 visitor->visit(j, element_value);
9981 }
9982 }
9983 break;
9984 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009985 case FAST_DOUBLE_ELEMENTS: {
9986 // TODO(1810): Decide if it's worthwhile to implement this.
9987 UNREACHABLE();
9988 break;
9989 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009990 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009991 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009992 List<uint32_t> indices(dict->Capacity() / 2);
9993 // Collect all indices in the object and the prototypes less
9994 // than length. This might introduce duplicates in the indices list.
9995 CollectElementIndices(receiver, length, &indices);
9996 indices.Sort(&compareUInt32);
9997 int j = 0;
9998 int n = indices.length();
9999 while (j < n) {
10000 HandleScope loop_scope;
10001 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010002 Handle<Object> element = Object::GetElement(receiver, index);
10003 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 visitor->visit(index, element);
10005 // Skip to next different index (i.e., omit duplicates).
10006 do {
10007 j++;
10008 } while (j < n && indices[j] == index);
10009 }
10010 break;
10011 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010012 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010013 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10014 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010015 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010016 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010017 visitor->visit(j, e);
10018 }
10019 break;
10020 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010021 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010022 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010023 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010024 break;
10025 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010026 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010028 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010029 break;
10030 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010031 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010033 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010034 break;
10035 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010036 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010038 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010039 break;
10040 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010041 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010044 break;
10045 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010046 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 break;
10050 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010051 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010053 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010054 break;
10055 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010056 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010057 IterateExternalArrayElements<ExternalDoubleArray, double>(
10058 isolate, receiver, false, false, visitor);
10059 break;
10060 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010061 default:
10062 UNREACHABLE();
10063 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010064 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010065 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010066 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010067}
10068
10069
10070/**
10071 * Array::concat implementation.
10072 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010073 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010074 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010075 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010076RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010077 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010078 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010079
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010080 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010081 int argument_count = static_cast<int>(arguments->length()->Number());
10082 RUNTIME_ASSERT(arguments->HasFastElements());
10083 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010084
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010085 // Pass 1: estimate the length and number of elements of the result.
10086 // The actual length can be larger if any of the arguments have getters
10087 // that mutate other arguments (but will otherwise be precise).
10088 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010089
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010090 uint32_t estimate_result_length = 0;
10091 uint32_t estimate_nof_elements = 0;
10092 {
10093 for (int i = 0; i < argument_count; i++) {
10094 HandleScope loop_scope;
10095 Handle<Object> obj(elements->get(i));
10096 uint32_t length_estimate;
10097 uint32_t element_estimate;
10098 if (obj->IsJSArray()) {
10099 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010100 // TODO(1810): Find out if it's worthwhile to properly support
10101 // arbitrary ElementsKinds. For now, pessimistically transition to
10102 // FAST_ELEMENTS.
10103 if (array->HasFastDoubleElements()) {
10104 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010105 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010106 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010107 length_estimate =
10108 static_cast<uint32_t>(array->length()->Number());
10109 element_estimate =
10110 EstimateElementCount(array);
10111 } else {
10112 length_estimate = 1;
10113 element_estimate = 1;
10114 }
10115 // Avoid overflows by capping at kMaxElementCount.
10116 if (JSObject::kMaxElementCount - estimate_result_length <
10117 length_estimate) {
10118 estimate_result_length = JSObject::kMaxElementCount;
10119 } else {
10120 estimate_result_length += length_estimate;
10121 }
10122 if (JSObject::kMaxElementCount - estimate_nof_elements <
10123 element_estimate) {
10124 estimate_nof_elements = JSObject::kMaxElementCount;
10125 } else {
10126 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010127 }
10128 }
10129 }
10130
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010131 // If estimated number of elements is more than half of length, a
10132 // fixed array (fast case) is more time and space-efficient than a
10133 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010134 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010135
10136 Handle<FixedArray> storage;
10137 if (fast_case) {
10138 // The backing storage array must have non-existing elements to
10139 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010140 storage = isolate->factory()->NewFixedArrayWithHoles(
10141 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010142 } else {
10143 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10144 uint32_t at_least_space_for = estimate_nof_elements +
10145 (estimate_nof_elements >> 2);
10146 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010147 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010148 }
10149
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010150 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010151
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010152 for (int i = 0; i < argument_count; i++) {
10153 Handle<Object> obj(elements->get(i));
10154 if (obj->IsJSArray()) {
10155 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010156 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010157 return Failure::Exception();
10158 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010159 } else {
10160 visitor.visit(0, obj);
10161 visitor.increase_index_offset(1);
10162 }
10163 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010164
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010165 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010166}
10167
10168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010169// This will not allocate (flatten the string), but it may run
10170// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010171RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 NoHandleAllocation ha;
10173 ASSERT(args.length() == 1);
10174
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010175 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176 StringInputBuffer buffer(string);
10177 while (buffer.has_more()) {
10178 uint16_t character = buffer.GetNext();
10179 PrintF("%c", character);
10180 }
10181 return string;
10182}
10183
ager@chromium.org5ec48922009-05-05 07:25:34 +000010184// Moves all own elements of an object, that are below a limit, to positions
10185// starting at zero. All undefined values are placed after non-undefined values,
10186// and are followed by non-existing element. Does not change the length
10187// property.
10188// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010189RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010190 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010191 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010192 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10193 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010194}
10195
10196
10197// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010198RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010200 CONVERT_ARG_CHECKED(JSArray, from, 0);
10201 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010202 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010203 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010204 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010205 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10206 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010207 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010208 } else if (new_elements->map() ==
10209 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010210 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010211 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010212 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010213 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010214 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010215 Object* new_map;
10216 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010217 to->set_map(Map::cast(new_map));
10218 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010220 Object* obj;
10221 { MaybeObject* maybe_obj = from->ResetElements();
10222 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10223 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010224 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010225 return to;
10226}
10227
10228
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010229// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010230RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010231 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010232 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010233 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010234 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010235 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10236 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010237 } else if (object->IsJSArray()) {
10238 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010240 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241 }
10242}
10243
10244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010245RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010246 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010247
10248 ASSERT_EQ(3, args.length());
10249
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010250 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010251 Handle<Object> key1 = args.at<Object>(1);
10252 Handle<Object> key2 = args.at<Object>(2);
10253
10254 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010255 if (!key1->ToArrayIndex(&index1)
10256 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010257 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010258 }
10259
ager@chromium.orgac091b72010-05-05 07:34:42 +000010260 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010261 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010262 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010263 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010264 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010265
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010266 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010267 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010268 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010269 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010270
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010272}
10273
10274
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010276// might have elements. Can either return keys (positive integers) or
10277// intervals (pair of a negative integer (-start-1) followed by a
10278// positive (length)) or undefined values.
10279// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010280RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010282 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010283 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010285 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 // Create an array and get all the keys into it, then remove all the
10287 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010288 bool threw = false;
10289 Handle<FixedArray> keys =
10290 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10291 if (threw) return Failure::Exception();
10292
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010293 int keys_length = keys->length();
10294 for (int i = 0; i < keys_length; i++) {
10295 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010296 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010297 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 // Zap invalid keys.
10299 keys->set_undefined(i);
10300 }
10301 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010302 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010304 ASSERT(array->HasFastElements() ||
10305 array->HasFastSmiOnlyElements() ||
10306 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010307 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010309 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010310 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010311 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010312 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010313 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010315 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010316 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010317 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318 }
10319}
10320
10321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010322RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010324 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10325 CONVERT_ARG_CHECKED(String, name, 1);
10326 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010327 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10328 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329}
10330
10331
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010332#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010333RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010334 ASSERT(args.length() == 0);
10335 return Execution::DebugBreakHelper();
10336}
10337
10338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339// Helper functions for wrapping and unwrapping stack frame ids.
10340static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010341 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342 return Smi::FromInt(id >> 2);
10343}
10344
10345
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010346static StackFrame::Id UnwrapFrameId(int wrapped) {
10347 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348}
10349
10350
10351// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010352// args[0]: debug event listener function to set or null or undefined for
10353// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010355RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010356 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010357 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10358 args[0]->IsUndefined() ||
10359 args[0]->IsNull());
10360 Handle<Object> callback = args.at<Object>(0);
10361 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010362 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010365}
10366
10367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010368RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010369 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 isolate->stack_guard()->DebugBreak();
10371 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372}
10373
10374
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010375static MaybeObject* DebugLookupResultValue(Heap* heap,
10376 Object* receiver,
10377 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010378 LookupResult* result,
10379 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010380 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010382 case NORMAL:
10383 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010384 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010385 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386 }
10387 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010388 case FIELD:
10389 value =
10390 JSObject::cast(
10391 result->holder())->FastPropertyAt(result->GetFieldIndex());
10392 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010393 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010394 }
10395 return value;
10396 case CONSTANT_FUNCTION:
10397 return result->GetConstantFunction();
10398 case CALLBACKS: {
10399 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010400 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010401 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10402 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010403 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010404 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010405 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010406 maybe_value = heap->isolate()->pending_exception();
10407 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010408 if (caught_exception != NULL) {
10409 *caught_exception = true;
10410 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010411 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010412 }
10413 return value;
10414 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010415 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010416 }
10417 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010418 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010419 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010420 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010421 case CONSTANT_TRANSITION:
10422 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010423 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010424 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010426 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010428 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010429 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430}
10431
10432
ager@chromium.org32912102009-01-16 10:38:43 +000010433// Get debugger related details for an object property.
10434// args[0]: object holding property
10435// args[1]: name of the property
10436//
10437// The array returned contains the following information:
10438// 0: Property value
10439// 1: Property details
10440// 2: Property value is exception
10441// 3: Getter function if defined
10442// 4: Setter function if defined
10443// Items 2-4 are only filled if the property has either a getter or a setter
10444// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010445RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010446 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010447
10448 ASSERT(args.length() == 2);
10449
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010450 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10451 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010452
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010453 // Make sure to set the current context to the context before the debugger was
10454 // entered (if the debugger is entered). The reason for switching context here
10455 // is that for some property lookups (accessors and interceptors) callbacks
10456 // into the embedding application can occour, and the embedding application
10457 // could have the assumption that its own global context is the current
10458 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010459 SaveContext save(isolate);
10460 if (isolate->debug()->InDebugger()) {
10461 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010462 }
10463
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010464 // Skip the global proxy as it has no properties and always delegates to the
10465 // real global object.
10466 if (obj->IsJSGlobalProxy()) {
10467 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10468 }
10469
10470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 // Check if the name is trivially convertible to an index and get the element
10472 // if so.
10473 uint32_t index;
10474 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010475 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010476 Object* element_or_char;
10477 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010478 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010479 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10480 return maybe_element_or_char;
10481 }
10482 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010483 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010484 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010485 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486 }
10487
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010488 // Find the number of objects making up this.
10489 int length = LocalPrototypeChainLength(*obj);
10490
10491 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010492 Handle<JSObject> jsproto = obj;
10493 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010494 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010495 jsproto->LocalLookup(*name, &result);
10496 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010497 // LookupResult is not GC safe as it holds raw object pointers.
10498 // GC can happen later in this code so put the required fields into
10499 // local variables using handles when required for later use.
10500 PropertyType result_type = result.type();
10501 Handle<Object> result_callback_obj;
10502 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10504 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010505 }
10506 Smi* property_details = result.GetPropertyDetails().AsSmi();
10507 // DebugLookupResultValue can cause GC so details from LookupResult needs
10508 // to be copied to handles before this.
10509 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010510 Object* raw_value;
10511 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010512 DebugLookupResultValue(isolate->heap(), *obj, *name,
10513 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010514 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10515 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010516 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010517
10518 // If the callback object is a fixed array then it contains JavaScript
10519 // getter and/or setter.
10520 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010521 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010522 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010524 details->set(0, *value);
10525 details->set(1, property_details);
10526 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010527 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010528 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010529 details->set(3, accessors->SafeGet(ACCESSOR_GETTER));
10530 details->set(4, accessors->SafeGet(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010531 }
10532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010534 }
10535 if (i < length - 1) {
10536 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10537 }
10538 }
10539
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010540 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010541}
10542
10543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010544RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010545 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010546
10547 ASSERT(args.length() == 2);
10548
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010549 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10550 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010552 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 obj->Lookup(*name, &result);
10554 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010555 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010557 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010558}
10559
10560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561// Return the property type calculated from the property details.
10562// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010563RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010565 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10566 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567}
10568
10569
10570// Return the property attribute calculated from the property details.
10571// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010572RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010574 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10575 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010576}
10577
10578
10579// Return the property insertion index calculated from the property details.
10580// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010583 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10584 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585}
10586
10587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588// Return property value from named interceptor.
10589// args[0]: object
10590// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010591RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010594 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010596 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597
10598 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010599 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600}
10601
10602
10603// Return element value from indexed interceptor.
10604// args[0]: object
10605// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010606RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010609 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10611 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10612
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010613 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614}
10615
10616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010617RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618 ASSERT(args.length() >= 1);
10619 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010620 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010621 if (isolate->debug()->break_id() == 0 ||
10622 break_id != isolate->debug()->break_id()) {
10623 return isolate->Throw(
10624 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010625 }
10626
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010627 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628}
10629
10630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010631RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010632 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010633 ASSERT(args.length() == 1);
10634
10635 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010636 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010637 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10638 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010639 if (!maybe_result->ToObject(&result)) return maybe_result;
10640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010641
10642 // Count all frames which are relevant to debugging stack trace.
10643 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010644 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010645 if (id == StackFrame::NO_ID) {
10646 // If there is no JavaScript stack frame count is 0.
10647 return Smi::FromInt(0);
10648 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010649
10650 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10651 n += it.frame()->GetInlineCount();
10652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653 return Smi::FromInt(n);
10654}
10655
10656
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010657class FrameInspector {
10658 public:
10659 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010660 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010661 Isolate* isolate)
10662 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10663 // Calculate the deoptimized frame.
10664 if (frame->is_optimized()) {
10665 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010666 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010667 }
10668 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010669 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010670 is_optimized_ = frame_->is_optimized();
10671 }
10672
10673 ~FrameInspector() {
10674 // Get rid of the calculated deoptimized frame if any.
10675 if (deoptimized_frame_ != NULL) {
10676 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10677 isolate_);
10678 }
10679 }
10680
10681 int GetParametersCount() {
10682 return is_optimized_
10683 ? deoptimized_frame_->parameters_count()
10684 : frame_->ComputeParametersCount();
10685 }
10686 int expression_count() { return deoptimized_frame_->expression_count(); }
10687 Object* GetFunction() {
10688 return is_optimized_
10689 ? deoptimized_frame_->GetFunction()
10690 : frame_->function();
10691 }
10692 Object* GetParameter(int index) {
10693 return is_optimized_
10694 ? deoptimized_frame_->GetParameter(index)
10695 : frame_->GetParameter(index);
10696 }
10697 Object* GetExpression(int index) {
10698 return is_optimized_
10699 ? deoptimized_frame_->GetExpression(index)
10700 : frame_->GetExpression(index);
10701 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010702 int GetSourcePosition() {
10703 return is_optimized_
10704 ? deoptimized_frame_->GetSourcePosition()
10705 : frame_->LookupCode()->SourcePosition(frame_->pc());
10706 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010707 bool IsConstructor() {
10708 return is_optimized_ && !is_bottommost_
10709 ? deoptimized_frame_->HasConstructStub()
10710 : frame_->IsConstructor();
10711 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010712
10713 // To inspect all the provided arguments the frame might need to be
10714 // replaced with the arguments frame.
10715 void SetArgumentsFrame(JavaScriptFrame* frame) {
10716 ASSERT(has_adapted_arguments_);
10717 frame_ = frame;
10718 is_optimized_ = frame_->is_optimized();
10719 ASSERT(!is_optimized_);
10720 }
10721
10722 private:
10723 JavaScriptFrame* frame_;
10724 DeoptimizedFrameInfo* deoptimized_frame_;
10725 Isolate* isolate_;
10726 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010727 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010728 bool has_adapted_arguments_;
10729
10730 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10731};
10732
10733
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734static const int kFrameDetailsFrameIdIndex = 0;
10735static const int kFrameDetailsReceiverIndex = 1;
10736static const int kFrameDetailsFunctionIndex = 2;
10737static const int kFrameDetailsArgumentCountIndex = 3;
10738static const int kFrameDetailsLocalCountIndex = 4;
10739static const int kFrameDetailsSourcePositionIndex = 5;
10740static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010741static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010742static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010743static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010745
10746static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10747 JavaScriptFrame* frame) {
10748 SaveContext* save = isolate->save_context();
10749 while (save != NULL && !save->IsBelowFrame(frame)) {
10750 save = save->prev();
10751 }
10752 ASSERT(save != NULL);
10753 return save;
10754}
10755
10756
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757// Return an array with frame details
10758// args[0]: number: break id
10759// args[1]: number: frame index
10760//
10761// The array returned contains the following information:
10762// 0: Frame id
10763// 1: Receiver
10764// 2: Function
10765// 3: Argument count
10766// 4: Local count
10767// 5: Source position
10768// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010769// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010770// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771// Arguments name, value
10772// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010773// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010774RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010775 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 ASSERT(args.length() == 2);
10777
10778 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010779 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010780 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10781 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010782 if (!maybe_check->ToObject(&check)) return maybe_check;
10783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010784 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010785 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786
10787 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010788 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010789 if (id == StackFrame::NO_ID) {
10790 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010791 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010792 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010795 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010796 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010797 if (index < count + it.frame()->GetInlineCount()) break;
10798 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010800 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010801
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010802 bool is_optimized = it.frame()->is_optimized();
10803
10804 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10805 if (is_optimized) {
10806 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010807 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010808 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010809 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010810
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010811 // Traverse the saved contexts chain to find the active context for the
10812 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010813 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814
10815 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010816 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010817
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010818 // Find source position in unoptimized code.
10819 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820
ulan@chromium.org967e2702012-02-28 09:49:15 +000010821 // Check for constructor frame.
10822 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010823
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010824 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010825 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010826 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010827 Handle<ScopeInfo> scope_info(shared->scope_info());
10828 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010830 // Get the locals names and values into a temporary array.
10831 //
10832 // TODO(1240907): Hide compiler-introduced stack variables
10833 // (e.g. .result)? For users of the debugger, they will probably be
10834 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010835 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010836 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010838 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010839 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010840 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010841 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010842 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010843 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010844 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010845 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010846 // Get the context containing declarations.
10847 Handle<Context> context(
10848 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010849 for (; i < scope_info->LocalCount(); ++i) {
10850 Handle<String> name(scope_info->LocalName(i));
10851 VariableMode mode;
10852 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010853 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010854 locals->set(i * 2 + 1, context->get(
10855 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856 }
10857 }
10858
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010859 // Check whether this frame is positioned at return. If not top
10860 // frame or if the frame is optimized it cannot be at a return.
10861 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010862 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010863 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010864 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010865
10866 // If positioned just before return find the value to be returned and add it
10867 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010868 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010869 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010870 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010871 Address internal_frame_sp = NULL;
10872 while (!it2.done()) {
10873 if (it2.frame()->is_internal()) {
10874 internal_frame_sp = it2.frame()->sp();
10875 } else {
10876 if (it2.frame()->is_java_script()) {
10877 if (it2.frame()->id() == it.frame()->id()) {
10878 // The internal frame just before the JavaScript frame contains the
10879 // value to return on top. A debug break at return will create an
10880 // internal frame to store the return value (eax/rax/r0) before
10881 // entering the debug break exit frame.
10882 if (internal_frame_sp != NULL) {
10883 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010884 Handle<Object>(Memory::Object_at(internal_frame_sp),
10885 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010886 break;
10887 }
10888 }
10889 }
10890
10891 // Indicate that the previous frame was not an internal frame.
10892 internal_frame_sp = NULL;
10893 }
10894 it2.Advance();
10895 }
10896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010897
10898 // Now advance to the arguments adapter frame (if any). It contains all
10899 // the provided parameters whereas the function frame always have the number
10900 // of arguments matching the functions parameters. The rest of the
10901 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010902 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010903 it.AdvanceToArgumentsFrame();
10904 frame_inspector.SetArgumentsFrame(it.frame());
10905 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010906
10907 // Find the number of arguments to fill. At least fill the number of
10908 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010909 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010910 if (argument_count < frame_inspector.GetParametersCount()) {
10911 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912 }
10913
10914 // Calculate the size of the result.
10915 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010916 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010917 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010918 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919
10920 // Add the frame id.
10921 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10922
10923 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010924 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925
10926 // Add the arguments count.
10927 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10928
10929 // Add the locals count
10930 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010931 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932
10933 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010934 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010935 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10936 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010937 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938 }
10939
10940 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010941 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010942
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010943 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010944 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010945
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010946 // Add flags to indicate information on whether this frame is
10947 // bit 0: invoked in the debugger context.
10948 // bit 1: optimized frame.
10949 // bit 2: inlined in optimized frame
10950 int flags = 0;
10951 if (*save->context() == *isolate->debug()->debug_context()) {
10952 flags |= 1 << 0;
10953 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010954 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010955 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010956 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010957 }
10958 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959
10960 // Fill the dynamic part.
10961 int details_index = kFrameDetailsFirstDynamicIndex;
10962
10963 // Add arguments name and value.
10964 for (int i = 0; i < argument_count; i++) {
10965 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010966 if (i < scope_info->ParameterCount()) {
10967 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010969 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010970 }
10971
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010972 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010973 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010974 // Get the value from the stack.
10975 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010976 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010977 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978 }
10979 }
10980
10981 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010982 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983 details->set(details_index++, locals->get(i));
10984 }
10985
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010986 // Add the value being returned.
10987 if (at_return) {
10988 details->set(details_index++, *return_value);
10989 }
10990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991 // Add the receiver (same as in function frame).
10992 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10993 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010994 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010995 if (!receiver->IsJSObject() &&
10996 shared->is_classic_mode() &&
10997 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010998 // If the receiver is not a JSObject and the function is not a
10999 // builtin or strict-mode we have hit an optimization where a
11000 // value object is not converted into a wrapped JS objects. To
11001 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011002 // by creating correct wrapper object based on the calling frame's
11003 // global context.
11004 it.Advance();
11005 Handle<Context> calling_frames_global_context(
11006 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011007 receiver =
11008 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009 }
11010 details->set(kFrameDetailsReceiverIndex, *receiver);
11011
11012 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014}
11015
11016
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011018static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011019 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011020 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011021 Handle<Context> context,
11022 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011023 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011024 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11025 VariableMode mode;
11026 InitializationFlag init_flag;
11027 int context_index = scope_info->ContextSlotIndex(
11028 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011029
whesse@chromium.org7b260152011-06-20 15:33:18 +000011030 RETURN_IF_EMPTY_HANDLE_VALUE(
11031 isolate,
11032 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011033 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011034 Handle<Object>(context->get(context_index), isolate),
11035 NONE,
11036 kNonStrictMode),
11037 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011038 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011039
11040 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011041}
11042
11043
11044// Create a plain JSObject which materializes the local scope for the specified
11045// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011046static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011047 Isolate* isolate,
11048 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011049 FrameInspector* frame_inspector) {
11050 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011051 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011052 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011053
11054 // Allocate and initialize a JSObject with all the arguments, stack locals
11055 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011056 Handle<JSObject> local_scope =
11057 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011058
11059 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011060 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011061 Handle<Object> value(
11062 i < frame_inspector->GetParametersCount() ?
11063 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11064
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011065 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011066 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011067 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011068 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011069 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011070 NONE,
11071 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011072 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073 }
11074
11075 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011076 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011077 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011078 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011079 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011080 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011081 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011082 NONE,
11083 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011084 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011085 }
11086
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011087 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011088 // Third fill all context locals.
11089 Handle<Context> frame_context(Context::cast(frame->context()));
11090 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011091 if (!CopyContextLocalsToScopeObject(
11092 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011093 return Handle<JSObject>();
11094 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011095
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011096 // Finally copy any properties from the function context extension.
11097 // These will be variables introduced by eval.
11098 if (function_context->closure() == *function) {
11099 if (function_context->has_extension() &&
11100 !function_context->IsGlobalContext()) {
11101 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011102 bool threw = false;
11103 Handle<FixedArray> keys =
11104 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11105 if (threw) return Handle<JSObject>();
11106
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011107 for (int i = 0; i < keys->length(); i++) {
11108 // Names of variables introduced by eval are strings.
11109 ASSERT(keys->get(i)->IsString());
11110 Handle<String> key(String::cast(keys->get(i)));
11111 RETURN_IF_EMPTY_HANDLE_VALUE(
11112 isolate,
11113 SetProperty(local_scope,
11114 key,
11115 GetProperty(ext, key),
11116 NONE,
11117 kNonStrictMode),
11118 Handle<JSObject>());
11119 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011120 }
11121 }
11122 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011123
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 return local_scope;
11125}
11126
11127
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011128static Handle<JSObject> MaterializeLocalScope(
11129 Isolate* isolate,
11130 JavaScriptFrame* frame,
11131 int inlined_jsframe_index) {
11132 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11133 return MaterializeLocalScopeWithFrameInspector(isolate,
11134 frame,
11135 &frame_inspector);
11136}
11137
11138
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011139// Create a plain JSObject which materializes the closure content for the
11140// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011141static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11142 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011143 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011145 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011146 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011147
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011148 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011149 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150 Handle<JSObject> closure_scope =
11151 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011152
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011153 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011154 if (!CopyContextLocalsToScopeObject(
11155 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011156 return Handle<JSObject>();
11157 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011158
11159 // Finally copy any properties from the function context extension. This will
11160 // be variables introduced by eval.
11161 if (context->has_extension()) {
11162 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011163 bool threw = false;
11164 Handle<FixedArray> keys =
11165 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11166 if (threw) return Handle<JSObject>();
11167
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011168 for (int i = 0; i < keys->length(); i++) {
11169 // Names of variables introduced by eval are strings.
11170 ASSERT(keys->get(i)->IsString());
11171 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011172 RETURN_IF_EMPTY_HANDLE_VALUE(
11173 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011174 SetProperty(closure_scope,
11175 key,
11176 GetProperty(ext, key),
11177 NONE,
11178 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011179 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180 }
11181 }
11182
11183 return closure_scope;
11184}
11185
11186
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011187// Create a plain JSObject which materializes the scope for the specified
11188// catch context.
11189static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11190 Handle<Context> context) {
11191 ASSERT(context->IsCatchContext());
11192 Handle<String> name(String::cast(context->extension()));
11193 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11194 Handle<JSObject> catch_scope =
11195 isolate->factory()->NewJSObject(isolate->object_function());
11196 RETURN_IF_EMPTY_HANDLE_VALUE(
11197 isolate,
11198 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11199 Handle<JSObject>());
11200 return catch_scope;
11201}
11202
11203
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011204// Create a plain JSObject which materializes the block scope for the specified
11205// block context.
11206static Handle<JSObject> MaterializeBlockScope(
11207 Isolate* isolate,
11208 Handle<Context> context) {
11209 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011210 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011211
11212 // Allocate and initialize a JSObject with all the arguments, stack locals
11213 // heap locals and extension properties of the debugged function.
11214 Handle<JSObject> block_scope =
11215 isolate->factory()->NewJSObject(isolate->object_function());
11216
11217 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011218 if (!CopyContextLocalsToScopeObject(
11219 isolate, scope_info, context, block_scope)) {
11220 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011221 }
11222
11223 return block_scope;
11224}
11225
11226
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011227// Create a plain JSObject which materializes the module scope for the specified
11228// module context.
11229static Handle<JSObject> MaterializeModuleScope(
11230 Isolate* isolate,
11231 Handle<Context> context) {
11232 ASSERT(context->IsModuleContext());
11233 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11234
11235 // Allocate and initialize a JSObject with all the members of the debugged
11236 // module.
11237 Handle<JSObject> module_scope =
11238 isolate->factory()->NewJSObject(isolate->object_function());
11239
11240 // Fill all context locals.
11241 if (!CopyContextLocalsToScopeObject(
11242 isolate, scope_info, context, module_scope)) {
11243 return Handle<JSObject>();
11244 }
11245
11246 return module_scope;
11247}
11248
11249
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011250// Iterate over the actual scopes visible from a stack frame. The iteration
11251// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011252// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011253// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011254class ScopeIterator {
11255 public:
11256 enum ScopeType {
11257 ScopeTypeGlobal = 0,
11258 ScopeTypeLocal,
11259 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011260 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011261 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011262 ScopeTypeBlock,
11263 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011264 };
11265
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011266 ScopeIterator(Isolate* isolate,
11267 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011268 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011269 : isolate_(isolate),
11270 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011271 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011272 function_(JSFunction::cast(frame->function())),
11273 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011274 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011275
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011276 // Catch the case when the debugger stops in an internal function.
11277 Handle<SharedFunctionInfo> shared_info(function_->shared());
11278 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11279 if (shared_info->script() == isolate->heap()->undefined_value()) {
11280 while (context_->closure() == *function_) {
11281 context_ = Handle<Context>(context_->previous(), isolate_);
11282 }
11283 return;
11284 }
11285
11286 // Get the debug info (create it if it does not exist).
11287 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11288 // Return if ensuring debug info failed.
11289 return;
11290 }
11291 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11292
11293 // Find the break point where execution has stopped.
11294 BreakLocationIterator break_location_iterator(debug_info,
11295 ALL_BREAK_LOCATIONS);
11296 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11297 if (break_location_iterator.IsExit()) {
11298 // We are within the return sequence. At the momemt it is not possible to
11299 // get a source position which is consistent with the current scope chain.
11300 // Thus all nested with, catch and block contexts are skipped and we only
11301 // provide the function scope.
11302 if (scope_info->HasContext()) {
11303 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11304 } else {
11305 while (context_->closure() == *function_) {
11306 context_ = Handle<Context>(context_->previous(), isolate_);
11307 }
11308 }
11309 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11310 } else {
11311 // Reparse the code and analyze the scopes.
11312 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11313 Handle<Script> script(Script::cast(shared_info->script()));
11314 Scope* scope = NULL;
11315
11316 // Check whether we are in global, eval or function code.
11317 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11318 if (scope_info->Type() != FUNCTION_SCOPE) {
11319 // Global or eval code.
11320 CompilationInfo info(script);
11321 if (scope_info->Type() == GLOBAL_SCOPE) {
11322 info.MarkAsGlobal();
11323 } else {
11324 ASSERT(scope_info->Type() == EVAL_SCOPE);
11325 info.MarkAsEval();
11326 info.SetCallingContext(Handle<Context>(function_->context()));
11327 }
11328 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11329 scope = info.function()->scope();
11330 }
11331 } else {
11332 // Function code
11333 CompilationInfo info(shared_info);
11334 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11335 scope = info.function()->scope();
11336 }
11337 }
11338
11339 // Retrieve the scope chain for the current position.
11340 if (scope != NULL) {
11341 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11342 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11343 } else {
11344 // A failed reparse indicates that the preparser has diverged from the
11345 // parser or that the preparse data given to the initial parse has been
11346 // faulty. We fail in debug mode but in release mode we only provide the
11347 // information we get from the context chain but nothing about
11348 // completely stack allocated scopes or stack allocated locals.
11349 UNREACHABLE();
11350 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011351 }
11352 }
11353
11354 // More scopes?
11355 bool Done() { return context_.is_null(); }
11356
11357 // Move to the next scope.
11358 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011359 ScopeType scope_type = Type();
11360 if (scope_type == ScopeTypeGlobal) {
11361 // The global scope is always the last in the chain.
11362 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011363 context_ = Handle<Context>();
11364 return;
11365 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011366 if (nested_scope_chain_.is_empty()) {
11367 context_ = Handle<Context>(context_->previous(), isolate_);
11368 } else {
11369 if (nested_scope_chain_.last()->HasContext()) {
11370 ASSERT(context_->previous() != NULL);
11371 context_ = Handle<Context>(context_->previous(), isolate_);
11372 }
11373 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011374 }
11375 }
11376
11377 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011378 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011379 if (!nested_scope_chain_.is_empty()) {
11380 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11381 switch (scope_info->Type()) {
11382 case FUNCTION_SCOPE:
11383 ASSERT(context_->IsFunctionContext() ||
11384 !scope_info->HasContext());
11385 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011386 case MODULE_SCOPE:
11387 ASSERT(context_->IsModuleContext());
11388 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011389 case GLOBAL_SCOPE:
11390 ASSERT(context_->IsGlobalContext());
11391 return ScopeTypeGlobal;
11392 case WITH_SCOPE:
11393 ASSERT(context_->IsWithContext());
11394 return ScopeTypeWith;
11395 case CATCH_SCOPE:
11396 ASSERT(context_->IsCatchContext());
11397 return ScopeTypeCatch;
11398 case BLOCK_SCOPE:
11399 ASSERT(!scope_info->HasContext() ||
11400 context_->IsBlockContext());
11401 return ScopeTypeBlock;
11402 case EVAL_SCOPE:
11403 UNREACHABLE();
11404 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011405 }
11406 if (context_->IsGlobalContext()) {
11407 ASSERT(context_->global()->IsGlobalObject());
11408 return ScopeTypeGlobal;
11409 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011410 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011411 return ScopeTypeClosure;
11412 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011413 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011414 return ScopeTypeCatch;
11415 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011416 if (context_->IsBlockContext()) {
11417 return ScopeTypeBlock;
11418 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011419 if (context_->IsModuleContext()) {
11420 return ScopeTypeModule;
11421 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011422 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011423 return ScopeTypeWith;
11424 }
11425
11426 // Return the JavaScript object with the content of the current scope.
11427 Handle<JSObject> ScopeObject() {
11428 switch (Type()) {
11429 case ScopeIterator::ScopeTypeGlobal:
11430 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011431 case ScopeIterator::ScopeTypeLocal:
11432 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011433 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011434 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011435 case ScopeIterator::ScopeTypeWith:
11436 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011437 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11438 case ScopeIterator::ScopeTypeCatch:
11439 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011440 case ScopeIterator::ScopeTypeClosure:
11441 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011442 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011443 case ScopeIterator::ScopeTypeBlock:
11444 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011445 case ScopeIterator::ScopeTypeModule:
11446 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011447 }
11448 UNREACHABLE();
11449 return Handle<JSObject>();
11450 }
11451
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011452 Handle<ScopeInfo> CurrentScopeInfo() {
11453 if (!nested_scope_chain_.is_empty()) {
11454 return nested_scope_chain_.last();
11455 } else if (context_->IsBlockContext()) {
11456 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11457 } else if (context_->IsFunctionContext()) {
11458 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11459 }
11460 return Handle<ScopeInfo>::null();
11461 }
11462
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011463 // Return the context for this scope. For the local context there might not
11464 // be an actual context.
11465 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011466 if (Type() == ScopeTypeGlobal ||
11467 nested_scope_chain_.is_empty()) {
11468 return context_;
11469 } else if (nested_scope_chain_.last()->HasContext()) {
11470 return context_;
11471 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011472 return Handle<Context>();
11473 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011474 }
11475
11476#ifdef DEBUG
11477 // Debug print of the content of the current scope.
11478 void DebugPrint() {
11479 switch (Type()) {
11480 case ScopeIterator::ScopeTypeGlobal:
11481 PrintF("Global:\n");
11482 CurrentContext()->Print();
11483 break;
11484
11485 case ScopeIterator::ScopeTypeLocal: {
11486 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011487 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011488 if (!CurrentContext().is_null()) {
11489 CurrentContext()->Print();
11490 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011491 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011492 if (extension->IsJSContextExtensionObject()) {
11493 extension->Print();
11494 }
11495 }
11496 }
11497 break;
11498 }
11499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011500 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011502 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011503 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011504
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011505 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011506 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011507 CurrentContext()->extension()->Print();
11508 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011509 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011511 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011512 PrintF("Closure:\n");
11513 CurrentContext()->Print();
11514 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011515 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011516 if (extension->IsJSContextExtensionObject()) {
11517 extension->Print();
11518 }
11519 }
11520 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011521
11522 default:
11523 UNREACHABLE();
11524 }
11525 PrintF("\n");
11526 }
11527#endif
11528
11529 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011531 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011532 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011533 Handle<JSFunction> function_;
11534 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011535 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011536
11537 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11538};
11539
11540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011541RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011542 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011543 ASSERT(args.length() == 2);
11544
11545 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011546 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011547 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11548 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011549 if (!maybe_check->ToObject(&check)) return maybe_check;
11550 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011551 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011552
11553 // Get the frame where the debugging is performed.
11554 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011555 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011556 JavaScriptFrame* frame = it.frame();
11557
11558 // Count the visible scopes.
11559 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011560 for (ScopeIterator it(isolate, frame, 0);
11561 !it.Done();
11562 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011563 n++;
11564 }
11565
11566 return Smi::FromInt(n);
11567}
11568
11569
11570static const int kScopeDetailsTypeIndex = 0;
11571static const int kScopeDetailsObjectIndex = 1;
11572static const int kScopeDetailsSize = 2;
11573
11574// Return an array with scope details
11575// args[0]: number: break id
11576// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011577// args[2]: number: inlined frame index
11578// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011579//
11580// The array returned contains the following information:
11581// 0: Scope type
11582// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011583RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011584 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011585 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011586
11587 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011588 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011589 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11590 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011591 if (!maybe_check->ToObject(&check)) return maybe_check;
11592 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011593 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011594 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011595 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011596
11597 // Get the frame where the debugging is performed.
11598 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011599 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011600 JavaScriptFrame* frame = frame_it.frame();
11601
11602 // Find the requested scope.
11603 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011604 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011605 for (; !it.Done() && n < index; it.Next()) {
11606 n++;
11607 }
11608 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011610 }
11611
11612 // Calculate the size of the result.
11613 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011615
11616 // Fill in scope details.
11617 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011618 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011619 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011620 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011621
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011622 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011623}
11624
11625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011626RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011628 ASSERT(args.length() == 0);
11629
11630#ifdef DEBUG
11631 // Print the scopes for the top frame.
11632 StackFrameLocator locator;
11633 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011634 for (ScopeIterator it(isolate, frame, 0);
11635 !it.Done();
11636 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011637 it.DebugPrint();
11638 }
11639#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011641}
11642
11643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011644RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011646 ASSERT(args.length() == 1);
11647
11648 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011649 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011650 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11651 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011652 if (!maybe_result->ToObject(&result)) return maybe_result;
11653 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011654
11655 // Count all archived V8 threads.
11656 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 for (ThreadState* thread =
11658 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011659 thread != NULL;
11660 thread = thread->Next()) {
11661 n++;
11662 }
11663
11664 // Total number of threads is current thread and archived threads.
11665 return Smi::FromInt(n + 1);
11666}
11667
11668
11669static const int kThreadDetailsCurrentThreadIndex = 0;
11670static const int kThreadDetailsThreadIdIndex = 1;
11671static const int kThreadDetailsSize = 2;
11672
11673// Return an array with thread details
11674// args[0]: number: break id
11675// args[1]: number: thread index
11676//
11677// The array returned contains the following information:
11678// 0: Is current thread?
11679// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011680RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011682 ASSERT(args.length() == 2);
11683
11684 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011685 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011686 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11687 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011688 if (!maybe_check->ToObject(&check)) return maybe_check;
11689 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011690 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11691
11692 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011693 Handle<FixedArray> details =
11694 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011695
11696 // Thread index 0 is current thread.
11697 if (index == 0) {
11698 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 details->set(kThreadDetailsCurrentThreadIndex,
11700 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011701 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011702 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011703 } else {
11704 // Find the thread with the requested index.
11705 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011706 ThreadState* thread =
11707 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011708 while (index != n && thread != NULL) {
11709 thread = thread->Next();
11710 n++;
11711 }
11712 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011713 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011714 }
11715
11716 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011717 details->set(kThreadDetailsCurrentThreadIndex,
11718 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011719 details->set(kThreadDetailsThreadIdIndex,
11720 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011721 }
11722
11723 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011725}
11726
11727
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011728// Sets the disable break state
11729// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011731 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011733 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011734 isolate->debug()->set_disable_break(disable_break);
11735 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011736}
11737
11738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011739RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011740 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011741 ASSERT(args.length() == 1);
11742
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011743 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011744 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745 // Find the number of break points
11746 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011749 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750 Handle<FixedArray>::cast(break_locations));
11751}
11752
11753
11754// Set a break point in a function
11755// args[0]: function
11756// args[1]: number: break source position (within the function source)
11757// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011758RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011761 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011762 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11764 RUNTIME_ASSERT(source_position >= 0);
11765 Handle<Object> break_point_object_arg = args.at<Object>(2);
11766
11767 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011768 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11769 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011770
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011771 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772}
11773
11774
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011775Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11776 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011777 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778 // Iterate the heap looking for SharedFunctionInfo generated from the
11779 // script. The inner most SharedFunctionInfo containing the source position
11780 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011781 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011782 // which is found is not compiled it is compiled and the heap is iterated
11783 // again as the compilation might create inner functions from the newly
11784 // compiled function and the actual requested break point might be in one of
11785 // these functions.
11786 bool done = false;
11787 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011788 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011791 { // Extra scope for iterator and no-allocation.
11792 isolate->heap()->EnsureHeapIsIterable();
11793 AssertNoAllocation no_alloc_during_heap_iteration;
11794 HeapIterator iterator;
11795 for (HeapObject* obj = iterator.next();
11796 obj != NULL; obj = iterator.next()) {
11797 if (obj->IsSharedFunctionInfo()) {
11798 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11799 if (shared->script() == *script) {
11800 // If the SharedFunctionInfo found has the requested script data and
11801 // contains the source position it is a candidate.
11802 int start_position = shared->function_token_position();
11803 if (start_position == RelocInfo::kNoPosition) {
11804 start_position = shared->start_position();
11805 }
11806 if (start_position <= position &&
11807 position <= shared->end_position()) {
11808 // If there is no candidate or this function is within the current
11809 // candidate this is the new candidate.
11810 if (target.is_null()) {
11811 target_start_position = start_position;
11812 target = shared;
11813 } else {
11814 if (target_start_position == start_position &&
11815 shared->end_position() == target->end_position()) {
11816 // If a top-level function contain only one function
11817 // declartion the source for the top-level and the
11818 // function is the same. In that case prefer the non
11819 // top-level function.
11820 if (!shared->is_toplevel()) {
11821 target_start_position = start_position;
11822 target = shared;
11823 }
11824 } else if (target_start_position <= start_position &&
11825 shared->end_position() <= target->end_position()) {
11826 // This containment check includes equality as a function
11827 // inside a top-level function can share either start or end
11828 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011829 target_start_position = start_position;
11830 target = shared;
11831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011832 }
11833 }
11834 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011835 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011836 } // End for loop.
11837 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011840 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 }
11842
11843 // If the candidate found is compiled we are done. NOTE: when lazy
11844 // compilation of inner functions is introduced some additional checking
11845 // needs to be done here to compile inner functions.
11846 done = target->is_compiled();
11847 if (!done) {
11848 // If the candidate is not compiled compile it to reveal any inner
11849 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011850 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011852 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853
11854 return *target;
11855}
11856
11857
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011858// Changes the state of a break point in a script and returns source position
11859// where break point was set. NOTE: Regarding performance see the NOTE for
11860// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861// args[0]: script to set break point in
11862// args[1]: number: break source position (within the script source)
11863// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011864RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011867 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011868 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11869 RUNTIME_ASSERT(source_position >= 0);
11870 Handle<Object> break_point_object_arg = args.at<Object>(2);
11871
11872 // Get the script from the script wrapper.
11873 RUNTIME_ASSERT(wrapper->value()->IsScript());
11874 Handle<Script> script(Script::cast(wrapper->value()));
11875
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011876 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878 if (!result->IsUndefined()) {
11879 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11880 // Find position within function. The script position might be before the
11881 // source position of the first function.
11882 int position;
11883 if (shared->start_position() > source_position) {
11884 position = 0;
11885 } else {
11886 position = source_position - shared->start_position();
11887 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011888 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011889 position += shared->start_position();
11890 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893}
11894
11895
11896// Clear a break point
11897// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011898RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900 ASSERT(args.length() == 1);
11901 Handle<Object> break_point_object_arg = args.at<Object>(0);
11902
11903 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011906 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907}
11908
11909
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011910// Change the state of break on exceptions.
11911// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11912// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011913RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011914 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011916 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011917 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011919 // If the number doesn't match an enum value, the ChangeBreakOnException
11920 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921 ExceptionBreakType type =
11922 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011923 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924 isolate->debug()->ChangeBreakOnException(type, enable);
11925 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011926}
11927
11928
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011929// Returns the state of break on exceptions
11930// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011931RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011933 ASSERT(args.length() == 1);
11934 RUNTIME_ASSERT(args[0]->IsNumber());
11935
11936 ExceptionBreakType type =
11937 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011938 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011939 return Smi::FromInt(result);
11940}
11941
11942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011943// Prepare for stepping
11944// args[0]: break id for checking execution state
11945// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011946// args[2]: number of times to perform the step, for step out it is the number
11947// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011948RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011950 ASSERT(args.length() == 3);
11951 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011952 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011953 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11954 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011955 if (!maybe_check->ToObject(&check)) return maybe_check;
11956 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011957 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011958 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011959 }
11960
11961 // Get the step action and check validity.
11962 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11963 if (step_action != StepIn &&
11964 step_action != StepNext &&
11965 step_action != StepOut &&
11966 step_action != StepInMin &&
11967 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011968 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969 }
11970
11971 // Get the number of steps.
11972 int step_count = NumberToInt32(args[2]);
11973 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011974 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011975 }
11976
ager@chromium.orga1645e22009-09-09 19:27:10 +000011977 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011978 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011981 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11982 step_count);
11983 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011984}
11985
11986
11987// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011988RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011989 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011990 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011991 isolate->debug()->ClearStepping();
11992 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011993}
11994
11995
11996// Creates a copy of the with context chain. The copy of the context chain is
11997// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011998static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11999 Handle<JSFunction> function,
12000 Handle<Context> base,
12001 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012002 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012003 HandleScope scope(isolate);
12004 List<Handle<ScopeInfo> > scope_chain;
12005 List<Handle<Context> > context_chain;
12006
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012007 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012008 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12009 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12010 ASSERT(!it.Done());
12011 scope_chain.Add(it.CurrentScopeInfo());
12012 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012013 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012014
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012015 // At the end of the chain. Return the base context to link to.
12016 Handle<Context> context = base;
12017
12018 // Iteratively copy and or materialize the nested contexts.
12019 while (!scope_chain.is_empty()) {
12020 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12021 Handle<Context> current = context_chain.RemoveLast();
12022 ASSERT(!(scope_info->HasContext() & current.is_null()));
12023
12024 if (scope_info->Type() == CATCH_SCOPE) {
12025 Handle<String> name(String::cast(current->extension()));
12026 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12027 context =
12028 isolate->factory()->NewCatchContext(function,
12029 context,
12030 name,
12031 thrown_object);
12032 } else if (scope_info->Type() == BLOCK_SCOPE) {
12033 // Materialize the contents of the block scope into a JSObject.
12034 Handle<JSObject> block_scope_object =
12035 MaterializeBlockScope(isolate, current);
12036 if (block_scope_object.is_null()) {
12037 return Handle<Context>::null();
12038 }
12039 // Allocate a new function context for the debug evaluation and set the
12040 // extension object.
12041 Handle<Context> new_context =
12042 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12043 function);
12044 new_context->set_extension(*block_scope_object);
12045 new_context->set_previous(*context);
12046 context = new_context;
12047 } else {
12048 ASSERT(scope_info->Type() == WITH_SCOPE);
12049 ASSERT(current->IsWithContext());
12050 Handle<JSObject> extension(JSObject::cast(current->extension()));
12051 context =
12052 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012053 }
erikcorry0ad885c2011-11-21 13:51:57 +000012054 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012055
12056 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012057}
12058
12059
12060// Helper function to find or create the arguments object for
12061// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012062static Handle<Object> GetArgumentsObject(Isolate* isolate,
12063 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012064 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012065 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012066 Handle<Context> function_context) {
12067 // Try to find the value of 'arguments' to pass as parameter. If it is not
12068 // found (that is the debugged function does not reference 'arguments' and
12069 // does not support eval) then create an 'arguments' object.
12070 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012071 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012072 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012073 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012074 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075 }
12076 }
12077
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012078 if (scope_info->HasHeapAllocatedLocals()) {
12079 VariableMode mode;
12080 InitializationFlag init_flag;
12081 index = scope_info->ContextSlotIndex(
12082 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012083 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012084 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012085 }
12086 }
12087
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012088 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12089 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012090 Handle<JSObject> arguments =
12091 isolate->factory()->NewArgumentsObject(function, length);
12092 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012093
12094 AssertNoAllocation no_gc;
12095 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012096 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012097 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012098 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012099 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012100 return arguments;
12101}
12102
12103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012104static const char kSourceStr[] =
12105 "(function(arguments,__source__){return eval(__source__);})";
12106
12107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012108// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012109// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110// extension part has all the parameters and locals of the function on the
12111// stack frame. A function which calls eval with the code to evaluate is then
12112// compiled in this context and called in this context. As this context
12113// replaces the context of the function on the stack frame a new (empty)
12114// function is created as well to be used as the closure for the context.
12115// This function and the context acts as replacements for the function on the
12116// stack frame presenting the same view of the values of parameters and
12117// local variables as if the piece of JavaScript was evaluated at the point
12118// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012119RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012120 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121
12122 // Check the execution state and decode arguments frame and source to be
12123 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012124 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012125 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012126 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12127 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012128 if (!maybe_check_result->ToObject(&check_result)) {
12129 return maybe_check_result;
12130 }
12131 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012132 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012133 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012134 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12135 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012136 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012137
12138 // Handle the processing of break.
12139 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140
12141 // Get the frame where the debugging is performed.
12142 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012143 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012145 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12146 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012147 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012148
12149 // Traverse the saved contexts chain to find the active context for the
12150 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012151 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012153 SaveContext savex(isolate);
12154 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012155
12156 // Create the (empty) function replacing the function on the stack frame for
12157 // the purpose of evaluating in the context created below. It is important
12158 // that this function does not describe any parameters and local variables
12159 // in the context. If it does then this will cause problems with the lookup
12160 // in Context::Lookup, where context slots for parameters and local variables
12161 // are looked at before the extension object.
12162 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012163 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12164 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012165 go_between->set_context(function->context());
12166#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012167 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12168 ASSERT(go_between_scope_info->ParameterCount() == 0);
12169 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012170#endif
12171
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012172 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012173 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12174 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012175 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012176
12177 // Allocate a new context for the debug evaluation and set the extension
12178 // object build.
12179 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012180 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12181 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012182 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012183 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012184 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012185 Handle<Context> function_context;
12186 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012187 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012188 function_context = Handle<Context>(frame_context->declaration_context());
12189 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012190 context = CopyNestedScopeContextChain(isolate,
12191 go_between,
12192 context,
12193 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012194 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012195
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012196 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012197 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012198 context =
12199 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012200 }
12201
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012202 // Wrap the evaluation statement in a new function compiled in the newly
12203 // created context. The function has one parameter which has to be called
12204 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012205 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012206 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012209 isolate->factory()->NewStringFromAscii(
12210 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012211
12212 // Currently, the eval code will be executed in non-strict mode,
12213 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012214 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012215 Compiler::CompileEval(function_source,
12216 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012217 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012218 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012219 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012220 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012222 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223
12224 // Invoke the result of the compilation to get the evaluation function.
12225 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012226 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227 Handle<Object> evaluation_function =
12228 Execution::Call(compiled_function, receiver, 0, NULL,
12229 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012230 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012232 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012233 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012234 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012235 scope_info,
12236 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237
12238 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012239 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012240 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012241 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12242 receiver,
12243 ARRAY_SIZE(argv),
12244 argv,
12245 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012246 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012247
12248 // Skip the global proxy as it has no properties and always delegates to the
12249 // real global object.
12250 if (result->IsJSGlobalProxy()) {
12251 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12252 }
12253
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012254 return *result;
12255}
12256
12257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012258RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012259 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012260
12261 // Check the execution state and decode arguments frame and source to be
12262 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012263 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012264 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012265 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12266 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012267 if (!maybe_check_result->ToObject(&check_result)) {
12268 return maybe_check_result;
12269 }
12270 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012271 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12272 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012273 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012274
12275 // Handle the processing of break.
12276 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012277
12278 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012279 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012280 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012281 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282 top = top->prev();
12283 }
12284 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012285 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012286 }
12287
12288 // Get the global context now set to the top context from before the
12289 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012290 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012291
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012292 bool is_global = true;
12293
12294 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012295 // Create a new with context with the additional context information between
12296 // the context of the debugged function and the eval code to be executed.
12297 context = isolate->factory()->NewWithContext(
12298 Handle<JSFunction>(context->closure()),
12299 context,
12300 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012301 is_global = false;
12302 }
12303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012305 // Currently, the eval code will be executed in non-strict mode,
12306 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012307 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012308 Compiler::CompileEval(source,
12309 context,
12310 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012311 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012312 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012313 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012314 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012315 Handle<JSFunction>(
12316 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12317 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318
12319 // Invoke the result of the compilation to get the evaluation function.
12320 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012321 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012322 Handle<Object> result =
12323 Execution::Call(compiled_function, receiver, 0, NULL,
12324 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012325 // Clear the oneshot breakpoints so that the debugger does not step further.
12326 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012327 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012328 return *result;
12329}
12330
12331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012332RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012333 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012334 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012335
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012336 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012337 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012338
12339 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012340 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012341 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12342 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12343 // because using
12344 // instances->set(i, *GetScriptWrapper(script))
12345 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012346 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012347 Handle<JSValue> wrapper = GetScriptWrapper(script);
12348 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012349 }
12350
12351 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012352 Handle<JSObject> result =
12353 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012354 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012355 return *result;
12356}
12357
12358
12359// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012360static int DebugReferencedBy(HeapIterator* iterator,
12361 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012362 Object* instance_filter, int max_references,
12363 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012364 JSFunction* arguments_function) {
12365 NoHandleAllocation ha;
12366 AssertNoAllocation no_alloc;
12367
12368 // Iterate the heap.
12369 int count = 0;
12370 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012371 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012372 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012373 (max_references == 0 || count < max_references)) {
12374 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012375 if (heap_obj->IsJSObject()) {
12376 // Skip context extension objects and argument arrays as these are
12377 // checked in the context of functions using them.
12378 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012379 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012380 obj->map()->constructor() == arguments_function) {
12381 continue;
12382 }
12383
12384 // Check if the JS object has a reference to the object looked for.
12385 if (obj->ReferencesObject(target)) {
12386 // Check instance filter if supplied. This is normally used to avoid
12387 // references from mirror objects (see Runtime_IsInPrototypeChain).
12388 if (!instance_filter->IsUndefined()) {
12389 Object* V = obj;
12390 while (true) {
12391 Object* prototype = V->GetPrototype();
12392 if (prototype->IsNull()) {
12393 break;
12394 }
12395 if (instance_filter == prototype) {
12396 obj = NULL; // Don't add this object.
12397 break;
12398 }
12399 V = prototype;
12400 }
12401 }
12402
12403 if (obj != NULL) {
12404 // Valid reference found add to instance array if supplied an update
12405 // count.
12406 if (instances != NULL && count < instances_size) {
12407 instances->set(count, obj);
12408 }
12409 last = obj;
12410 count++;
12411 }
12412 }
12413 }
12414 }
12415
12416 // Check for circular reference only. This can happen when the object is only
12417 // referenced from mirrors and has a circular reference in which case the
12418 // object is not really alive and would have been garbage collected if not
12419 // referenced from the mirror.
12420 if (count == 1 && last == target) {
12421 count = 0;
12422 }
12423
12424 // Return the number of referencing objects found.
12425 return count;
12426}
12427
12428
12429// Scan the heap for objects with direct references to an object
12430// args[0]: the object to find references to
12431// args[1]: constructor function for instances to exclude (Mirror)
12432// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012433RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012434 ASSERT(args.length() == 3);
12435
12436 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012437 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12438 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012439 // The heap iterator reserves the right to do a GC to make the heap iterable.
12440 // Due to the GC above we know it won't need to do that, but it seems cleaner
12441 // to get the heap iterator constructed before we start having unprotected
12442 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012443
12444 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012445 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012446 Object* instance_filter = args[1];
12447 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12448 instance_filter->IsJSObject());
12449 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12450 RUNTIME_ASSERT(max_references >= 0);
12451
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012453 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012454 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012455 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012456 JSFunction* arguments_function =
12457 JSFunction::cast(arguments_boilerplate->map()->constructor());
12458
12459 // Get the number of referencing objects.
12460 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012461 HeapIterator heap_iterator;
12462 count = DebugReferencedBy(&heap_iterator,
12463 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012464 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012465
12466 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012467 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012468 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012469 if (!maybe_object->ToObject(&object)) return maybe_object;
12470 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012471 FixedArray* instances = FixedArray::cast(object);
12472
12473 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012474 // AllocateFixedArray above does not make the heap non-iterable.
12475 ASSERT(HEAP->IsHeapIterable());
12476 HeapIterator heap_iterator2;
12477 count = DebugReferencedBy(&heap_iterator2,
12478 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012479 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012480
12481 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012482 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012483 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012484 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012485 if (!maybe_result->ToObject(&result)) return maybe_result;
12486 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012487}
12488
12489
12490// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012491static int DebugConstructedBy(HeapIterator* iterator,
12492 JSFunction* constructor,
12493 int max_references,
12494 FixedArray* instances,
12495 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012496 AssertNoAllocation no_alloc;
12497
12498 // Iterate the heap.
12499 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012500 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012501 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012502 (max_references == 0 || count < max_references)) {
12503 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012504 if (heap_obj->IsJSObject()) {
12505 JSObject* obj = JSObject::cast(heap_obj);
12506 if (obj->map()->constructor() == constructor) {
12507 // Valid reference found add to instance array if supplied an update
12508 // count.
12509 if (instances != NULL && count < instances_size) {
12510 instances->set(count, obj);
12511 }
12512 count++;
12513 }
12514 }
12515 }
12516
12517 // Return the number of referencing objects found.
12518 return count;
12519}
12520
12521
12522// Scan the heap for objects constructed by a specific function.
12523// args[0]: the constructor to find instances of
12524// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012525RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012526 ASSERT(args.length() == 2);
12527
12528 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012529 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12530 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012531
12532 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012533 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012534 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12535 RUNTIME_ASSERT(max_references >= 0);
12536
12537 // Get the number of referencing objects.
12538 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012539 HeapIterator heap_iterator;
12540 count = DebugConstructedBy(&heap_iterator,
12541 constructor,
12542 max_references,
12543 NULL,
12544 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012545
12546 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012547 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012548 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012549 if (!maybe_object->ToObject(&object)) return maybe_object;
12550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012551 FixedArray* instances = FixedArray::cast(object);
12552
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012553 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012554 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012555 HeapIterator heap_iterator2;
12556 count = DebugConstructedBy(&heap_iterator2,
12557 constructor,
12558 max_references,
12559 instances,
12560 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012561
12562 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012563 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012564 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12565 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012566 if (!maybe_result->ToObject(&result)) return maybe_result;
12567 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012568 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012569}
12570
12571
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012572// Find the effective prototype object as returned by __proto__.
12573// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012574RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012575 ASSERT(args.length() == 1);
12576
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012577 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012578
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012579 // Use the __proto__ accessor.
12580 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012581}
12582
12583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012584RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012585 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012586 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012587 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012588}
12589
12590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012591RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012592#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012593 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012594 ASSERT(args.length() == 1);
12595 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012596 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012597 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012598 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012599 return Failure::Exception();
12600 }
12601 func->code()->PrintLn();
12602#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012604}
ager@chromium.org9085a012009-05-11 19:22:57 +000012605
12606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012607RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012608#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012609 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012610 ASSERT(args.length() == 1);
12611 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012612 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012613 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012614 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012615 return Failure::Exception();
12616 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012617 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012618#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012619 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012620}
12621
12622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012623RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012624 NoHandleAllocation ha;
12625 ASSERT(args.length() == 1);
12626
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012627 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012628 return f->shared()->inferred_name();
12629}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012630
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012631
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012632static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12633 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012634 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012635 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012636 int counter = 0;
12637 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012638 for (HeapObject* obj = iterator->next();
12639 obj != NULL;
12640 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012641 ASSERT(obj != NULL);
12642 if (!obj->IsSharedFunctionInfo()) {
12643 continue;
12644 }
12645 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12646 if (shared->script() != script) {
12647 continue;
12648 }
12649 if (counter < buffer_size) {
12650 buffer->set(counter, shared);
12651 }
12652 counter++;
12653 }
12654 return counter;
12655}
12656
12657// For a script finds all SharedFunctionInfo's in the heap that points
12658// to this script. Returns JSArray of SharedFunctionInfo wrapped
12659// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012660RUNTIME_FUNCTION(MaybeObject*,
12661 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012662 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012663 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012664 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012665
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012666
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012667 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12668
12669 const int kBufferSize = 32;
12670
12671 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012672 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012673 int number;
12674 {
12675 isolate->heap()->EnsureHeapIsIterable();
12676 AssertNoAllocation no_allocations;
12677 HeapIterator heap_iterator;
12678 Script* scr = *script;
12679 FixedArray* arr = *array;
12680 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12681 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012682 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012684 isolate->heap()->EnsureHeapIsIterable();
12685 AssertNoAllocation no_allocations;
12686 HeapIterator heap_iterator;
12687 Script* scr = *script;
12688 FixedArray* arr = *array;
12689 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012690 }
12691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012692 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012693 result->set_length(Smi::FromInt(number));
12694
12695 LiveEdit::WrapSharedFunctionInfos(result);
12696
12697 return *result;
12698}
12699
12700// For a script calculates compilation information about all its functions.
12701// The script source is explicitly specified by the second argument.
12702// The source of the actual script is not used, however it is important that
12703// all generated code keeps references to this particular instance of script.
12704// Returns a JSArray of compilation infos. The array is ordered so that
12705// each function with all its descendant is always stored in a continues range
12706// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012707RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012708 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012709 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012710 CONVERT_ARG_CHECKED(JSValue, script, 0);
12711 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012712 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12713
12714 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12715
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012716 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012717 return Failure::Exception();
12718 }
12719
12720 return result;
12721}
12722
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012723// Changes the source of the script to a new_source.
12724// If old_script_name is provided (i.e. is a String), also creates a copy of
12725// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012726RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012727 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012728 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012729 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12730 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012731 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012732
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012733 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12734 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012735
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012736 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12737 new_source,
12738 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012739
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012740 if (old_script->IsScript()) {
12741 Handle<Script> script_handle(Script::cast(old_script));
12742 return *(GetScriptWrapper(script_handle));
12743 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012744 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012745 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012746}
12747
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012749RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012750 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012751 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012752 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012753 return LiveEdit::FunctionSourceUpdated(shared_info);
12754}
12755
12756
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012757// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012758RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012759 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012760 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012761 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12762 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012763
ager@chromium.orgac091b72010-05-05 07:34:42 +000012764 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012765}
12766
12767// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012768RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012769 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012770 HandleScope scope(isolate);
12771 Handle<Object> function_object(args[0], isolate);
12772 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012773
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012774 if (function_object->IsJSValue()) {
12775 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12776 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012777 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12778 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012779 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012780 }
12781
12782 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12783 } else {
12784 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12785 // and we check it in this function.
12786 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012789}
12790
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012791
12792// In a code of a parent function replaces original function as embedded object
12793// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012794RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012795 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012796 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012797
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012798 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12799 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12800 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012801
12802 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12803 subst_wrapper);
12804
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012805 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012806}
12807
12808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012809// Updates positions of a shared function info (first parameter) according
12810// to script source change. Text change is described in second parameter as
12811// array of groups of 3 numbers:
12812// (change_begin, change_end, change_end_new_position).
12813// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012814RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012815 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012816 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012817 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12818 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012819
ager@chromium.orgac091b72010-05-05 07:34:42 +000012820 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012821}
12822
12823
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012824// For array of SharedFunctionInfo's (each wrapped in JSValue)
12825// checks that none of them have activations on stacks (of any thread).
12826// Returns array of the same length with corresponding results of
12827// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012828RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012829 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012831 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12832 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012833
ager@chromium.org357bf652010-04-12 11:30:10 +000012834 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012835}
12836
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012837// Compares 2 strings line-by-line, then token-wise and returns diff in form
12838// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12839// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012840RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012841 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012843 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12844 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012845
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012846 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012847}
12848
12849
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012850// A testing entry. Returns statement position which is the closest to
12851// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012852RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012853 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012854 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012855 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012856 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012858 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012859
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012860 if (code->kind() != Code::FUNCTION &&
12861 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012862 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012863 }
12864
12865 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012866 int closest_pc = 0;
12867 int distance = kMaxInt;
12868 while (!it.done()) {
12869 int statement_position = static_cast<int>(it.rinfo()->data());
12870 // Check if this break point is closer that what was previously found.
12871 if (source_position <= statement_position &&
12872 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012873 closest_pc =
12874 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012875 distance = statement_position - source_position;
12876 // Check whether we can't get any closer.
12877 if (distance == 0) break;
12878 }
12879 it.next();
12880 }
12881
12882 return Smi::FromInt(closest_pc);
12883}
12884
12885
ager@chromium.org357bf652010-04-12 11:30:10 +000012886// Calls specified function with or without entering the debugger.
12887// This is used in unit tests to run code as if debugger is entered or simply
12888// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012889RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012890 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012891 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012892 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12893 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012894
12895 Handle<Object> result;
12896 bool pending_exception;
12897 {
12898 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012899 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012900 &pending_exception);
12901 } else {
12902 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012903 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012904 &pending_exception);
12905 }
12906 }
12907 if (!pending_exception) {
12908 return *result;
12909 } else {
12910 return Failure::Exception();
12911 }
12912}
12913
12914
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012915// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012916RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012917 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012918 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012919 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12920 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012921 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012922}
12923
12924
12925// Performs a GC.
12926// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012927RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012928 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012929 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012930}
12931
12932
12933// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012934RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012935 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012936 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012937 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012938 }
12939 return Smi::FromInt(usage);
12940}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012941
12942
12943// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012944RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012945#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012946 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012947#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012948 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012949#endif
12950}
12951
12952
12953// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012954RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012955#ifdef LIVE_OBJECT_LIST
12956 return LiveObjectList::Capture();
12957#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012958 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012959#endif
12960}
12961
12962
12963// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012964RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012965#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012966 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012967 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012968 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012969#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012970 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012971#endif
12972}
12973
12974
12975// Generates the response to a debugger request for a dump of the objects
12976// contained in the difference between the captured live object lists
12977// specified by id1 and id2.
12978// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12979// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012980RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012981#ifdef LIVE_OBJECT_LIST
12982 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012983 CONVERT_SMI_ARG_CHECKED(id1, 0);
12984 CONVERT_SMI_ARG_CHECKED(id2, 1);
12985 CONVERT_SMI_ARG_CHECKED(start, 2);
12986 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012987 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012988 EnterDebugger enter_debugger;
12989 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12990#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012991 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012992#endif
12993}
12994
12995
12996// Gets the specified object as requested by the debugger.
12997// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012998RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012999#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013000 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013001 Object* result = LiveObjectList::GetObj(obj_id);
13002 return result;
13003#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013004 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013005#endif
13006}
13007
13008
13009// Gets the obj id for the specified address if valid.
13010// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013011RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013012#ifdef LIVE_OBJECT_LIST
13013 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013014 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013015 Object* result = LiveObjectList::GetObjId(address);
13016 return result;
13017#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013018 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013019#endif
13020}
13021
13022
13023// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013024RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025#ifdef LIVE_OBJECT_LIST
13026 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013027 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013028 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13029 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13030 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13031 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013032 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013033
13034 Handle<JSObject> instance_filter;
13035 if (args[1]->IsJSObject()) {
13036 instance_filter = args.at<JSObject>(1);
13037 }
13038 bool verbose = false;
13039 if (args[2]->IsBoolean()) {
13040 verbose = args[2]->IsTrue();
13041 }
13042 int start = 0;
13043 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013044 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013045 }
13046 int limit = Smi::kMaxValue;
13047 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013048 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013049 }
13050
13051 return LiveObjectList::GetObjRetainers(obj_id,
13052 instance_filter,
13053 verbose,
13054 start,
13055 limit,
13056 filter_obj);
13057#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013058 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013059#endif
13060}
13061
13062
13063// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013064RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013065#ifdef LIVE_OBJECT_LIST
13066 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013067 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13068 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013069 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13070
13071 Handle<JSObject> instance_filter;
13072 if (args[2]->IsJSObject()) {
13073 instance_filter = args.at<JSObject>(2);
13074 }
13075
13076 Object* result =
13077 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13078 return result;
13079#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013080 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013081#endif
13082}
13083
13084
13085// Generates the response to a debugger request for a list of all
13086// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013087RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013088#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013089 CONVERT_SMI_ARG_CHECKED(start, 0);
13090 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013091 return LiveObjectList::Info(start, count);
13092#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013093 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013094#endif
13095}
13096
13097
13098// Gets a dump of the specified object as requested by the debugger.
13099// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013100RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013101#ifdef LIVE_OBJECT_LIST
13102 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013103 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013104 Object* result = LiveObjectList::PrintObj(obj_id);
13105 return result;
13106#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013107 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013108#endif
13109}
13110
13111
13112// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013113RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013114#ifdef LIVE_OBJECT_LIST
13115 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013116 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013117#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013118 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013119#endif
13120}
13121
13122
13123// Generates the response to a debugger request for a summary of the types
13124// of objects in the difference between the captured live object lists
13125// specified by id1 and id2.
13126// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13127// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013128RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013129#ifdef LIVE_OBJECT_LIST
13130 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013131 CONVERT_SMI_ARG_CHECKED(id1, 0);
13132 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013133 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013134
13135 EnterDebugger enter_debugger;
13136 return LiveObjectList::Summarize(id1, id2, filter_obj);
13137#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013138 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013139#endif
13140}
13141
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013142#endif // ENABLE_DEBUGGER_SUPPORT
13143
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013145RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013146 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013147 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013148 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013149}
13150
13151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013152RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013153 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013154 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013155 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013156}
13157
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013159// Finds the script object from the script data. NOTE: This operation uses
13160// heap traversal to find the function generated for the source position
13161// for the requested break point. For lazily compiled functions several heap
13162// traversals might be required rendering this operation as a rather slow
13163// operation. However for setting break points which is normally done through
13164// some kind of user interaction the performance is not crucial.
13165static Handle<Object> Runtime_GetScriptFromScriptName(
13166 Handle<String> script_name) {
13167 // Scan the heap for Script objects to find the script with the requested
13168 // script data.
13169 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013170 script_name->GetHeap()->EnsureHeapIsIterable();
13171 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013172 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013173 HeapObject* obj = NULL;
13174 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013175 // If a script is found check if it has the script data requested.
13176 if (obj->IsScript()) {
13177 if (Script::cast(obj)->name()->IsString()) {
13178 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13179 script = Handle<Script>(Script::cast(obj));
13180 }
13181 }
13182 }
13183 }
13184
13185 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013186 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013187
13188 // Return the script found.
13189 return GetScriptWrapper(script);
13190}
13191
13192
13193// Get the script object from script data. NOTE: Regarding performance
13194// see the NOTE for GetScriptFromScriptData.
13195// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013196RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013197 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013198
13199 ASSERT(args.length() == 1);
13200
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013201 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013202
13203 // Find the requested script.
13204 Handle<Object> result =
13205 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13206 return *result;
13207}
13208
13209
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013210// Determines whether the given stack frame should be displayed in
13211// a stack trace. The caller is the error constructor that asked
13212// for the stack trace to be collected. The first time a construct
13213// call to this function is encountered it is skipped. The seen_caller
13214// in/out parameter is used to remember if the caller has been seen
13215// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013216static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13217 Object* caller,
13218 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013219 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013220 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013221 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013222 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013223 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13224 Object* raw_fun = frame->function();
13225 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013226 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013227 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013228 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013229 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013230 *seen_caller = true;
13231 return false;
13232 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013233 // Skip all frames until we've seen the caller.
13234 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013235 // Also, skip non-visible built-in functions and any call with the builtins
13236 // object as receiver, so as to not reveal either the builtins object or
13237 // an internal function.
13238 // The --builtins-in-stack-traces command line flag allows including
13239 // internal call sites in the stack trace for debugging purposes.
13240 if (!FLAG_builtins_in_stack_traces) {
13241 JSFunction* fun = JSFunction::cast(raw_fun);
13242 if (frame->receiver()->IsJSBuiltinsObject() ||
13243 (fun->IsBuiltin() && !fun->shared()->native())) {
13244 return false;
13245 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013246 }
13247 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013248}
13249
13250
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013251// Collect the raw data for a stack trace. Returns an array of 4
13252// element segments each containing a receiver, function, code and
13253// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013254RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013255 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013256 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013257 Handle<Object> caller = args.at<Object>(1);
13258 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013259
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013260 HandleScope scope(isolate);
13261 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013262
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013263 limit = Max(limit, 0); // Ensure that limit is not negative.
13264 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013265 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013266 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013267
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013268 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013269 // If the caller parameter is a function we skip frames until we're
13270 // under it before starting to collect.
13271 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013272 int cursor = 0;
13273 int frames_seen = 0;
13274 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013275 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013276 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013277 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013278 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013279 // Set initial size to the maximum inlining level + 1 for the outermost
13280 // function.
13281 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013282 frame->Summarize(&frames);
13283 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013284 if (cursor + 4 > elements->length()) {
13285 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13286 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013287 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013288 for (int i = 0; i < cursor; i++) {
13289 new_elements->set(i, elements->get(i));
13290 }
13291 elements = new_elements;
13292 }
13293 ASSERT(cursor + 4 <= elements->length());
13294
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013295 Handle<Object> recv = frames[i].receiver();
13296 Handle<JSFunction> fun = frames[i].function();
13297 Handle<Code> code = frames[i].code();
13298 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013299 elements->set(cursor++, *recv);
13300 elements->set(cursor++, *fun);
13301 elements->set(cursor++, *code);
13302 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013303 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013304 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013305 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013306 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013307 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013308 // Capture and attach a more detailed stack trace if necessary.
13309 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013310 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013311 return *result;
13312}
13313
13314
ager@chromium.org3811b432009-10-28 14:53:37 +000013315// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013316RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013317 ASSERT_EQ(args.length(), 0);
13318
13319 NoHandleAllocation ha;
13320
13321 const char* version_string = v8::V8::GetVersion();
13322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013323 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13324 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013325}
13326
13327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013328RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013329 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013330 OS::PrintError("abort: %s\n",
13331 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013332 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013333 OS::Abort();
13334 UNREACHABLE();
13335 return NULL;
13336}
13337
13338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013339RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013340 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013341 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013342 Object* key = args[1];
13343
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013344 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013345 Object* o = cache->get(finger_index);
13346 if (o == key) {
13347 // The fastest case: hit the same place again.
13348 return cache->get(finger_index + 1);
13349 }
13350
13351 for (int i = finger_index - 2;
13352 i >= JSFunctionResultCache::kEntriesIndex;
13353 i -= 2) {
13354 o = cache->get(i);
13355 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013356 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013357 return cache->get(i + 1);
13358 }
13359 }
13360
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013361 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013362 ASSERT(size <= cache->length());
13363
13364 for (int i = size - 2; i > finger_index; i -= 2) {
13365 o = cache->get(i);
13366 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013367 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013368 return cache->get(i + 1);
13369 }
13370 }
13371
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013372 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013373 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013374
13375 Handle<JSFunctionResultCache> cache_handle(cache);
13376 Handle<Object> key_handle(key);
13377 Handle<Object> value;
13378 {
13379 Handle<JSFunction> factory(JSFunction::cast(
13380 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13381 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013382 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013383 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013384 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013385 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013386 value = Execution::Call(factory,
13387 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013388 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013389 argv,
13390 &pending_exception);
13391 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013392 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013393
13394#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013395 if (FLAG_verify_heap) {
13396 cache_handle->JSFunctionResultCacheVerify();
13397 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013398#endif
13399
13400 // Function invocation may have cleared the cache. Reread all the data.
13401 finger_index = cache_handle->finger_index();
13402 size = cache_handle->size();
13403
13404 // If we have spare room, put new data into it, otherwise evict post finger
13405 // entry which is likely to be the least recently used.
13406 int index = -1;
13407 if (size < cache_handle->length()) {
13408 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13409 index = size;
13410 } else {
13411 index = finger_index + JSFunctionResultCache::kEntrySize;
13412 if (index == cache_handle->length()) {
13413 index = JSFunctionResultCache::kEntriesIndex;
13414 }
13415 }
13416
13417 ASSERT(index % 2 == 0);
13418 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13419 ASSERT(index < cache_handle->length());
13420
13421 cache_handle->set(index, *key_handle);
13422 cache_handle->set(index + 1, *value);
13423 cache_handle->set_finger_index(index);
13424
13425#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013426 if (FLAG_verify_heap) {
13427 cache_handle->JSFunctionResultCacheVerify();
13428 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013429#endif
13430
13431 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013432}
13433
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013435RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013436 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013437 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13438 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013439 return *isolate->factory()->NewJSMessageObject(
13440 type,
13441 arguments,
13442 0,
13443 0,
13444 isolate->factory()->undefined_value(),
13445 isolate->factory()->undefined_value(),
13446 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013447}
13448
13449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013450RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013451 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013452 return message->type();
13453}
13454
13455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013456RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013457 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013458 return message->arguments();
13459}
13460
13461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013462RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013463 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013464 return Smi::FromInt(message->start_position());
13465}
13466
13467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013468RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013469 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013470 return message->script();
13471}
13472
13473
kasper.lund44510672008-07-25 07:37:58 +000013474#ifdef DEBUG
13475// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13476// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013477RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013478 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013479 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013480#define COUNT_ENTRY(Name, argc, ressize) + 1
13481 int entry_count = 0
13482 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13483 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13484 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13485#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013486 Factory* factory = isolate->factory();
13487 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013488 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013489 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013490#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013491 { \
13492 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013493 Handle<String> name; \
13494 /* Inline runtime functions have an underscore in front of the name. */ \
13495 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013496 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013497 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13498 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013499 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013500 Vector<const char>(#Name, StrLength(#Name))); \
13501 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013502 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013503 pair_elements->set(0, *name); \
13504 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013505 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013506 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013507 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013508 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013509 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013510 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013511 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013512 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013513#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013514 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013515 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013516 return *result;
13517}
kasper.lund44510672008-07-25 07:37:58 +000013518#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013519
13520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013521RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013522 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013523 CONVERT_ARG_CHECKED(String, format, 0);
13524 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013525 String::FlatContent format_content = format->GetFlatContent();
13526 RUNTIME_ASSERT(format_content.IsAscii());
13527 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013528 LOGGER->LogRuntime(chars, elms);
13529 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013530}
13531
13532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013533RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013534 UNREACHABLE(); // implemented as macro in the parser
13535 return NULL;
13536}
13537
13538
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013539#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13540 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013541 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013542 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13543 }
13544
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013545ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013546ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13547ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13548ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13549ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13550ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13551ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13552ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13553ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13554ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13555ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13556ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13557ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13558ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13559
13560#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13561
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013562
13563RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13564 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013565 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13566 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013567 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13568}
13569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013570// ----------------------------------------------------------------------------
13571// Implementation of Runtime
13572
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013573#define F(name, number_of_args, result_size) \
13574 { Runtime::k##name, Runtime::RUNTIME, #name, \
13575 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013576
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013577
13578#define I(name, number_of_args, result_size) \
13579 { Runtime::kInline##name, Runtime::INLINE, \
13580 "_" #name, NULL, number_of_args, result_size },
13581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013582static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013583 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013584 INLINE_FUNCTION_LIST(I)
13585 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013586};
13587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013588
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013589MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13590 Object* dictionary) {
13591 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013592 ASSERT(dictionary != NULL);
13593 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13594 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013595 Object* name_symbol;
13596 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013597 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013598 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13599 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013600 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013601 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13602 String::cast(name_symbol),
13603 Smi::FromInt(i),
13604 PropertyDetails(NONE, NORMAL));
13605 if (!maybe_dictionary->ToObject(&dictionary)) {
13606 // Non-recoverable failure. Calling code must restart heap
13607 // initialization.
13608 return maybe_dictionary;
13609 }
13610 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013611 }
13612 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013613}
13614
13615
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013616const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13617 Heap* heap = name->GetHeap();
13618 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013619 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013620 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013621 int function_index = Smi::cast(smi_index)->value();
13622 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013623 }
13624 return NULL;
13625}
13626
13627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013628const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013629 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13630}
13631
13632
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013633void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013634 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013635 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013636 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013637 if (isolate->heap()->new_space()->AddFreshPage()) {
13638 return;
13639 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013640 // Try to do a garbage collection; ignore it if it fails. The C
13641 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013642 isolate->heap()->CollectGarbage(failure->allocation_space(),
13643 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013644 } else {
13645 // Handle last resort GC and make sure to allow future allocations
13646 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013647 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013648 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13649 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013651}
13652
13653
13654} } // namespace v8::internal