blob: 29807da9f296e3e5e4bf33a89fa329793fffac0d [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 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.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
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.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000119MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
120 JSObject* boilerplate) {
121 StackLimitCheck check(isolate);
122 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 JSObject* copy = JSObject::cast(result);
130
131 // Deep copy local properties.
132 if (copy->HasFastProperties()) {
133 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 for (int i = 0; i < properties->length(); i++) {
135 Object* value = properties->get(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000144 int nof = copy->map()->inobject_properties();
145 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 Object* value = copy->InObjectPropertyAt(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
155 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 FixedArray* names = FixedArray::cast(result);
161 copy->GetLocalPropertyNames(names, 0);
162 for (int i = 0; i < names->length(); i++) {
163 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000166 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000167 // Only deep copy fields from the object literal expression.
168 // In particular, don't try to copy the length attribute of
169 // an array.
170 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 Object* value =
172 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 if (!maybe_result->ToObject(&result)) return maybe_result;
177 }
178 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000179 // Creating object copy for literals. No strict mode needed.
180 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000181 if (!maybe_result->ToObject(&result)) return maybe_result;
182 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 }
184 }
185 }
186
187 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000188 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000189 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000190 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000191 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000192 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000193 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 if (elements->map() == heap->fixed_cow_array_map()) {
195 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196#ifdef DEBUG
197 for (int i = 0; i < elements->length(); i++) {
198 ASSERT(!elements->get(i)->IsJSObject());
199 }
200#endif
201 } else {
202 for (int i = 0; i < elements->length(); i++) {
203 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204 ASSERT(value->IsSmi() ||
205 value->IsTheHole() ||
206 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207 if (value->IsJSObject()) {
208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000213 elements->set(i, result);
214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 }
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000219 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000220 NumberDictionary* element_dictionary = copy->element_dictionary();
221 int capacity = element_dictionary->Capacity();
222 for (int i = 0; i < capacity; i++) {
223 Object* k = element_dictionary->KeyAt(i);
224 if (element_dictionary->IsKey(k)) {
225 Object* value = element_dictionary->ValueAt(i);
226 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000227 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 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 element_dictionary->ValueAtPut(i, result);
233 }
234 }
235 }
236 break;
237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000239 UNIMPLEMENTED();
240 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000241 case EXTERNAL_PIXEL_ELEMENTS:
242 case EXTERNAL_BYTE_ELEMENTS:
243 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
244 case EXTERNAL_SHORT_ELEMENTS:
245 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
246 case EXTERNAL_INT_ELEMENTS:
247 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
248 case EXTERNAL_FLOAT_ELEMENTS:
249 case EXTERNAL_DOUBLE_ELEMENTS:
250 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000251 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000253 }
254 return copy;
255}
256
257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000258RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000259 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000261}
262
263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000264RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000266 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267}
268
269
ager@chromium.org236ad962008-09-25 09:45:57 +0000270static Handle<Map> ComputeObjectLiteralMap(
271 Handle<Context> context,
272 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000273 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 int properties_length = constant_properties->length();
276 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000278 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 for (int p = 0; p != properties_length; p += 2) {
281 Object* key = constant_properties->get(p);
282 uint32_t element_index = 0;
283 if (key->IsSymbol()) {
284 number_of_symbol_keys++;
285 } else if (key->ToArrayIndex(&element_index)) {
286 // An index key does not require space in the property backing store.
287 number_of_properties--;
288 } else {
289 // Bail out as a non-symbol non-index key makes caching impossible.
290 // ASSERT to make sure that the if condition after the loop is false.
291 ASSERT(number_of_symbol_keys != number_of_properties);
292 break;
293 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000294 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000295 // If we only have symbols and array indices among keys then we can
296 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 if ((number_of_symbol_keys == number_of_properties) &&
299 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Handle<FixedArray> keys =
302 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000303 if (number_of_symbol_keys > 0) {
304 int index = 0;
305 for (int p = 0; p < properties_length; p += 2) {
306 Object* key = constant_properties->get(p);
307 if (key->IsSymbol()) {
308 keys->set(index++, key);
309 }
310 }
311 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000313 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000315 }
316 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000317 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000319 Handle<Map>(context->object_function()->initial_map()),
320 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321}
322
323
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000324static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 Handle<FixedArray> literals,
327 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329
330static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000333 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000334 bool should_have_fast_elements,
335 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336 // Get the global context from the literals array. This is the
337 // context in which the function was created and we use the object
338 // function from this context to create the object literal. We do
339 // not use the object function from the current global context
340 // because this might be the object function from another context
341 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000342 Handle<Context> context =
343 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // In case we have function literals, we want the object to be in
346 // slow properties mode for now. We don't go in the map cache because
347 // maps with constant functions can't be shared if the functions are
348 // not the same (which is the common case).
349 bool is_result_from_cache = false;
350 Handle<Map> map = has_function_literal
351 ? Handle<Map>(context->object_function()->initial_map())
352 : ComputeObjectLiteralMap(context,
353 constant_properties,
354 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000357
358 // Normalize the elements of the boilerplate to save space if needed.
359 if (!should_have_fast_elements) NormalizeElements(boilerplate);
360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 // Add the constant properties to the boilerplate.
362 int length = constant_properties->length();
363 bool should_transform =
364 !is_result_from_cache && boilerplate->HasFastProperties();
365 if (should_transform || has_function_literal) {
366 // Normalize the properties of object to avoid n^2 behavior
367 // when extending the object multiple properties. Indicate the number of
368 // properties to be added.
369 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000387 result = SetOwnElement(boilerplate,
388 element_index,
389 value,
390 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 Handle<String> name(String::cast(*key));
393 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000394 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
395 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 } else if (key->ToArrayIndex(&element_index)) {
398 // Array index (uint32).
399 result = SetOwnElement(boilerplate,
400 element_index,
401 value,
402 kNonStrictMode);
403 } else {
404 // Non-uint32 number.
405 ASSERT(key->IsNumber());
406 double num = key->Number();
407 char arr[100];
408 Vector<char> buffer(arr, ARRAY_SIZE(arr));
409 const char* str = DoubleToCString(num, buffer);
410 Handle<String> name =
411 isolate->factory()->NewStringFromAscii(CStrVector(str));
412 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
413 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 // If setting the property on the boilerplate throws an
416 // exception, the exception is converted to an empty handle in
417 // the handle based operations. In that case, we need to
418 // convert back to an exception.
419 if (result.is_null()) return result;
420 }
421
422 // Transform to fast properties if necessary. For object literals with
423 // containing function literals we defer this operation until after all
424 // computed properties have been assigned so that we can generate
425 // constant function properties.
426 if (should_transform && !has_function_literal) {
427 TransformToFastProperties(boilerplate,
428 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
430
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000431 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000432}
433
434
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000435static const int kSmiOnlyLiteralMinimumLength = 1024;
436
437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541 default:
542 UNREACHABLE();
543 return Handle<Object>::null();
544 }
545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549 // Takes a FixedArray of elements containing the literal elements of
550 // the array literal and produces JSArray with those elements.
551 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552 // which contains the context from which to get the Array function
553 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000555 ASSERT(args.length() == 3);
556 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000557 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000558 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> object =
561 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000562 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *object);
566 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000572 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000576 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
578 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579
580 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 Handle<Object> boilerplate(literals->get(literals_index), isolate);
582 if (*boilerplate == isolate->heap()->undefined_value()) {
583 boilerplate = CreateObjectLiteralBoilerplate(isolate,
584 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000585 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 should_have_fast_elements,
587 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 if (boilerplate.is_null()) return Failure::Exception();
589 // Update the functions literal and return the boilerplate.
590 literals->set(literals_index, *boilerplate);
591 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593}
594
595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000596RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000598 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000600 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000602 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
604 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateObjectLiteralBoilerplate(isolate,
610 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000611 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 should_have_fast_elements,
613 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 if (boilerplate.is_null()) return Failure::Exception();
615 // Update the functions literal and return the boilerplate.
616 literals->set(literals_index, *boilerplate);
617 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619}
620
621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000622RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624 ASSERT(args.length() == 3);
625 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000626 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000627 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
628
629 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 Handle<Object> boilerplate(literals->get(literals_index), isolate);
631 if (*boilerplate == isolate->heap()->undefined_value()) {
632 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 if (boilerplate.is_null()) return Failure::Exception();
634 // Update the functions literal and return the boilerplate.
635 literals->set(literals_index, *boilerplate);
636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643 ASSERT(args.length() == 3);
644 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000645 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000646 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
647
648 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000649 Handle<Object> boilerplate(literals->get(literals_index), isolate);
650 if (*boilerplate == isolate->heap()->undefined_value()) {
651 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
703 CONVERT_CHECKED(JSProxy, proxy, args[0]);
704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
710 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
717 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
724 CONVERT_CHECKED(JSProxy, proxy, args[0]);
725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
755 CONVERT_ARG_CHECKED(JSSet, holder, 0);
756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSSet, holder, 0);
766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
777 CONVERT_ARG_CHECKED(JSMap, holder, 0);
778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
787 CONVERT_ARG_CHECKED(JSMap, holder, 0);
788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
796 CONVERT_ARG_CHECKED(JSMap, holder, 0);
797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
809 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
821 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
830 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000831 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
ager@chromium.org9085a012009-05-11 19:22:57 +0000886// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000887RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000888 NoHandleAllocation ha;
889 ASSERT(args.length() == 2);
890 CONVERT_CHECKED(JSObject, jsobject, args[0]);
891 CONVERT_CHECKED(JSObject, proto, args[1]);
892
893 // Sanity checks. The old prototype (that we are replacing) could
894 // theoretically be null, but if it is not null then check that we
895 // didn't already install a hidden prototype here.
896 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
897 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
898 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
899
900 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000901 Object* map_or_failure;
902 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
903 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
904 return maybe_map_or_failure;
905 }
906 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000907 Map* new_proto_map = Map::cast(map_or_failure);
908
lrn@chromium.org303ada72010-10-27 09:33:13 +0000909 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
910 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
911 return maybe_map_or_failure;
912 }
913 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000914 Map* new_map = Map::cast(map_or_failure);
915
916 // Set proto's prototype to be the old prototype of the object.
917 new_proto_map->set_prototype(jsobject->GetPrototype());
918 proto->set_map(new_proto_map);
919 new_proto_map->set_is_hidden_prototype();
920
921 // Set the object's prototype to proto.
922 new_map->set_prototype(proto);
923 jsobject->set_map(new_map);
924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000926}
927
928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000929RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000931 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000932 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934}
935
936
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000937// Recursively traverses hidden prototypes if property is not found
938static void GetOwnPropertyImplementation(JSObject* obj,
939 String* name,
940 LookupResult* result) {
941 obj->LocalLookupRealNamedProperty(name, result);
942
943 if (!result->IsProperty()) {
944 Object* proto = obj->GetPrototype();
945 if (proto->IsJSObject() &&
946 JSObject::cast(proto)->map()->is_hidden_prototype())
947 GetOwnPropertyImplementation(JSObject::cast(proto),
948 name, result);
949 }
950}
951
952
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000953static bool CheckAccessException(LookupResult* result,
954 v8::AccessType access_type) {
955 if (result->type() == CALLBACKS) {
956 Object* callback = result->GetCallbackObject();
957 if (callback->IsAccessorInfo()) {
958 AccessorInfo* info = AccessorInfo::cast(callback);
959 bool can_access =
960 (access_type == v8::ACCESS_HAS &&
961 (info->all_can_read() || info->all_can_write())) ||
962 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
963 (access_type == v8::ACCESS_SET && info->all_can_write());
964 return can_access;
965 }
966 }
967
968 return false;
969}
970
971
972static bool CheckAccess(JSObject* obj,
973 String* name,
974 LookupResult* result,
975 v8::AccessType access_type) {
976 ASSERT(result->IsProperty());
977
978 JSObject* holder = result->holder();
979 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000981 while (true) {
982 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000984 // Access check callback denied the access, but some properties
985 // can have a special permissions which override callbacks descision
986 // (currently see v8::AccessControl).
987 break;
988 }
989
990 if (current == holder) {
991 return true;
992 }
993
994 current = JSObject::cast(current->GetPrototype());
995 }
996
997 // API callbacks can have per callback access exceptions.
998 switch (result->type()) {
999 case CALLBACKS: {
1000 if (CheckAccessException(result, access_type)) {
1001 return true;
1002 }
1003 break;
1004 }
1005 case INTERCEPTOR: {
1006 // If the object has an interceptor, try real named properties.
1007 // Overwrite the result to fetch the correct property later.
1008 holder->LookupRealNamedProperty(name, result);
1009 if (result->IsProperty()) {
1010 if (CheckAccessException(result, access_type)) {
1011 return true;
1012 }
1013 }
1014 break;
1015 }
1016 default:
1017 break;
1018 }
1019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 return false;
1022}
1023
1024
1025// TODO(1095): we should traverse hidden prototype hierachy as well.
1026static bool CheckElementAccess(JSObject* obj,
1027 uint32_t index,
1028 v8::AccessType access_type) {
1029 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001031 return false;
1032 }
1033
1034 return true;
1035}
1036
1037
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001038// Enumerator used as indices into the array returned from GetOwnProperty
1039enum PropertyDescriptorIndices {
1040 IS_ACCESSOR_INDEX,
1041 VALUE_INDEX,
1042 GETTER_INDEX,
1043 SETTER_INDEX,
1044 WRITABLE_INDEX,
1045 ENUMERABLE_INDEX,
1046 CONFIGURABLE_INDEX,
1047 DESCRIPTOR_SIZE
1048};
1049
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001050// Returns an array with the property description:
1051// if args[1] is not a property on args[0]
1052// returns undefined
1053// if args[1] is a data property on args[0]
1054// [false, value, Writeable, Enumerable, Configurable]
1055// if args[1] is an accessor on args[0]
1056// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001057RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001058 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001059 Heap* heap = isolate->heap();
1060 HandleScope scope(isolate);
1061 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1062 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001063 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001064 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1065 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001066
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001067 // This could be an element.
1068 uint32_t index;
1069 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001070 switch (obj->HasLocalElement(index)) {
1071 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001073
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001074 case JSObject::STRING_CHARACTER_ELEMENT: {
1075 // Special handling of string objects according to ECMAScript 5
1076 // 15.5.5.2. Note that this might be a string object with elements
1077 // other than the actual string value. This is covered by the
1078 // subsequent cases.
1079 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1080 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001081 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(WRITABLE_INDEX, heap->false_value());
1086 elms->set(ENUMERABLE_INDEX, heap->false_value());
1087 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001088 return *desc;
1089 }
1090
1091 case JSObject::INTERCEPTED_ELEMENT:
1092 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001096 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 elms->set(WRITABLE_INDEX, heap->true_value());
1098 elms->set(ENUMERABLE_INDEX, heap->true_value());
1099 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001100 return *desc;
1101 }
1102
1103 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 Handle<JSObject> holder = obj;
1105 if (obj->IsJSGlobalProxy()) {
1106 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001107 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001108 ASSERT(proto->IsJSGlobalObject());
1109 holder = Handle<JSObject>(JSObject::cast(proto));
1110 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001111 FixedArray* elements = FixedArray::cast(holder->elements());
1112 NumberDictionary* dictionary = NULL;
1113 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1114 dictionary = NumberDictionary::cast(elements->get(1));
1115 } else {
1116 dictionary = NumberDictionary::cast(elements);
1117 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001118 int entry = dictionary->FindEntry(index);
1119 ASSERT(entry != NumberDictionary::kNotFound);
1120 PropertyDetails details = dictionary->DetailsAt(entry);
1121 switch (details.type()) {
1122 case CALLBACKS: {
1123 // This is an accessor property with getter and/or setter.
1124 FixedArray* callbacks =
1125 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001126 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001127 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1128 elms->set(GETTER_INDEX, callbacks->get(0));
1129 }
1130 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1131 elms->set(SETTER_INDEX, callbacks->get(1));
1132 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001133 break;
1134 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001135 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001136 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001138 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001139 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001140 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001142 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001143 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001144 default:
1145 UNREACHABLE();
1146 break;
1147 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1149 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001150 return *desc;
1151 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001152 }
1153 }
1154
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001155 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001156 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001157
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001158 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001159 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001160 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001161
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001162 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001163 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001164 }
1165
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001166 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1167 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001168
1169 bool is_js_accessor = (result.type() == CALLBACKS) &&
1170 (result.GetCallbackObject()->IsFixedArray());
1171
1172 if (is_js_accessor) {
1173 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001175
1176 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1177 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1178 elms->set(GETTER_INDEX, structure->get(0));
1179 }
1180 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1181 elms->set(SETTER_INDEX, structure->get(1));
1182 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001183 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1185 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001186
1187 PropertyAttributes attrs;
1188 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001189 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001190 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1191 if (!maybe_value->ToObject(&value)) return maybe_value;
1192 }
1193 elms->set(VALUE_INDEX, value);
1194 }
1195
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001196 return *desc;
1197}
1198
1199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001200RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001201 ASSERT(args.length() == 1);
1202 CONVERT_CHECKED(JSObject, obj, args[0]);
1203 return obj->PreventExtensions();
1204}
1205
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001207RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001208 ASSERT(args.length() == 1);
1209 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001210 if (obj->IsJSGlobalProxy()) {
1211 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001212 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001213 ASSERT(proto->IsJSGlobalObject());
1214 obj = JSObject::cast(proto);
1215 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001216 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001217}
1218
1219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001220RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001221 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001223 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1224 CONVERT_ARG_CHECKED(String, pattern, 1);
1225 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001226 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1227 if (result.is_null()) return Failure::Exception();
1228 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229}
1230
1231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001232RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001235 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237}
1238
1239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001240RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 ASSERT(args.length() == 1);
1242 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001243 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245}
1246
1247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001248RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 ASSERT(args.length() == 2);
1250 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001252 int index = field->value();
1253 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1254 InstanceType type = templ->map()->instance_type();
1255 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1256 type == OBJECT_TEMPLATE_INFO_TYPE);
1257 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001258 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001259 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1260 } else {
1261 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1262 }
1263 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264}
1265
1266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001267RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001268 ASSERT(args.length() == 1);
1269 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001270 Map* old_map = object->map();
1271 bool needs_access_checks = old_map->is_access_check_needed();
1272 if (needs_access_checks) {
1273 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001274 Object* new_map;
1275 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1276 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1277 }
ager@chromium.org32912102009-01-16 10:38:43 +00001278
1279 Map::cast(new_map)->set_is_access_check_needed(false);
1280 object->set_map(Map::cast(new_map));
1281 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001282 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001283}
1284
1285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001286RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001287 ASSERT(args.length() == 1);
1288 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001289 Map* old_map = object->map();
1290 if (!old_map->is_access_check_needed()) {
1291 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001292 Object* new_map;
1293 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1294 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1295 }
ager@chromium.org32912102009-01-16 10:38:43 +00001296
1297 Map::cast(new_map)->set_is_access_check_needed(true);
1298 object->set_map(Map::cast(new_map));
1299 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001300 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001301}
1302
1303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001304static Failure* ThrowRedeclarationError(Isolate* isolate,
1305 const char* type,
1306 Handle<String> name) {
1307 HandleScope scope(isolate);
1308 Handle<Object> type_handle =
1309 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 Handle<Object> args[2] = { type_handle, name };
1311 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001312 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1313 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314}
1315
1316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001317RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001318 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 HandleScope scope(isolate);
1320 Handle<GlobalObject> global = Handle<GlobalObject>(
1321 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322
ager@chromium.org3811b432009-10-28 14:53:37 +00001323 Handle<Context> context = args.at<Context>(0);
1324 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001325 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 // Traverse the name/value pairs and set the properties.
1328 int length = pairs->length();
1329 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001332 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333
1334 // We have to declare a global const property. To capture we only
1335 // assign to it when evaluating the assignment for "const x =
1336 // <expr>" the initial value is the hole.
1337 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001338 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 if (value->IsUndefined() || is_const_property) {
1340 // Lookup the property in the global object, and don't set the
1341 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001342 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 global->Lookup(*name, &lookup);
1344 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001345 // We found an existing property. Unless it was an interceptor
1346 // that claims the property is absent, skip this declaration.
1347 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 continue;
1349 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001350 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1351 if (attributes != ABSENT) {
1352 continue;
1353 }
1354 // Fall-through and introduce the absent property by using
1355 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001358 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001360 Handle<SharedFunctionInfo> shared =
1361 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1364 context,
1365 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 value = function;
1367 }
1368
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001369 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 global->LocalLookup(*name, &lookup);
1371
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001372 // Compute the property attributes. According to ECMA-262, section
1373 // 13, page 71, the property must be read-only and
1374 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1375 // property as read-only, so we don't either.
1376 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001377 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001378 attr |= DONT_DELETE;
1379 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001380 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001381 if (is_const_property || (is_native && is_function_declaration)) {
1382 attr |= READ_ONLY;
1383 }
1384
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001385 // Safari does not allow the invocation of callback setters for
1386 // function declarations. To mimic this behavior, we do not allow
1387 // the invocation of setters for function values. This makes a
1388 // difference for global functions with the same names as event
1389 // handlers such as "function onload() {}". Firefox does call the
1390 // onload setter in those case and Safari does not. We follow
1391 // Safari for compatibility.
1392 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001393 // Do not change DONT_DELETE to false from true.
1394 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001395 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001396 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001397 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 RETURN_IF_EMPTY_HANDLE(isolate,
1400 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001401 name,
1402 value,
1403 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001405 StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 RETURN_IF_EMPTY_HANDLE(isolate,
1407 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408 name,
1409 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001410 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001411 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 }
1413 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 ASSERT(!isolate->has_pending_exception());
1416 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417}
1418
1419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001420RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001422 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // Declarations are always made in a function or global context. In the
1425 // case of eval code, the context passed is the context of the caller,
1426 // which may be some nested context and not the declaration context.
1427 RUNTIME_ASSERT(args[0]->IsContext());
1428 Handle<Context> context(Context::cast(args[0])->declaration_context());
1429
ager@chromium.org7c537e22008-10-16 08:43:32 +00001430 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001431 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001432 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 int index;
1436 PropertyAttributes attributes;
1437 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001438 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001439 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001440 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441
1442 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001443 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1445 // Functions are not read-only.
1446 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1447 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001448 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 }
1450
1451 // Initialize it if necessary.
1452 if (*initial_value != NULL) {
1453 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 ASSERT(holder.is_identical_to(context));
1455 if (((attributes & READ_ONLY) == 0) ||
1456 context->get(index)->IsTheHole()) {
1457 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 }
1459 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001460 // Slow case: The property is in the context extension object of a
1461 // function context or the global object of a global context.
1462 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001463 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 }
1467 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001470 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001471 // "declared" in the function context's extension context or as a
1472 // property of the the global object.
1473 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001474 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001475 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001476 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001477 // Context extension objects are allocated lazily.
1478 ASSERT(context->IsFunctionContext());
1479 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001480 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001482 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
ager@chromium.org7c537e22008-10-16 08:43:32 +00001485 // Declare the property by setting it to the initial value if provided,
1486 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1487 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001489 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001490 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001491 // Declaring a const context slot is a conflicting declaration if
1492 // there is a callback with that name in a prototype. It is
1493 // allowed to introduce const variables in
1494 // JSContextExtensionObjects. They are treated specially in
1495 // SetProperty and no setters are invoked for those since they are
1496 // not real JSObjects.
1497 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001501 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001503 }
1504 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001507 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001508 }
1509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001510 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001511}
1512
1513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001514RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001516 // args[0] == name
1517 // args[1] == strict_mode
1518 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519
1520 // Determine if we need to assign to the variable if it already
1521 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001522 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1523 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524
1525 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001526 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 RUNTIME_ASSERT(args[1]->IsSmi());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001528 CONVERT_STRICT_MODE_ARG(strict_mode, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529
1530 // According to ECMA-262, section 12.2, page 62, the property must
1531 // not be deletable.
1532 PropertyAttributes attributes = DONT_DELETE;
1533
1534 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001535 // there, there is a property with this name in the prototype chain.
1536 // We follow Safari and Firefox behavior and only set the property
1537 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001538 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001539 // Note that objects can have hidden prototypes, so we need to traverse
1540 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001542 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543 while (object->IsJSObject() &&
1544 JSObject::cast(object)->map()->is_hidden_prototype()) {
1545 JSObject* raw_holder = JSObject::cast(object);
1546 raw_holder->LocalLookup(*name, &lookup);
1547 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1548 HandleScope handle_scope(isolate);
1549 Handle<JSObject> holder(raw_holder);
1550 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1551 // Update the raw pointer in case it's changed due to GC.
1552 raw_holder = *holder;
1553 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1554 // Found an interceptor that's not read only.
1555 if (assign) {
1556 return raw_holder->SetProperty(
1557 &lookup, *name, args[2], attributes, strict_mode);
1558 } else {
1559 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001560 }
1561 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001562 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 }
1565
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001568 if (assign) {
1569 return global->SetProperty(*name, args[2], attributes, strict_mode);
1570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572}
1573
1574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001575RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 // All constants are declared with an initial value. The name
1577 // of the constant is the first argument and the initial value
1578 // is the second.
1579 RUNTIME_ASSERT(args.length() == 2);
1580 CONVERT_ARG_CHECKED(String, name, 0);
1581 Handle<Object> value = args.at<Object>(1);
1582
1583 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001584 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585
1586 // According to ECMA-262, section 12.2, page 62, the property must
1587 // not be deletable. Since it's a const, it must be READ_ONLY too.
1588 PropertyAttributes attributes =
1589 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1590
1591 // Lookup the property locally in the global object. If it isn't
1592 // there, we add the property and take special precautions to always
1593 // add it as a local property even in case of callbacks in the
1594 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001595 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001596 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 global->LocalLookup(*name, &lookup);
1598 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001599 return global->SetLocalPropertyIgnoreAttributes(*name,
1600 *value,
1601 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 }
1603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001606 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 HandleScope handle_scope(isolate);
1608 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001610 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 // property through an interceptor and only do it if it's
1612 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001613 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001614 RETURN_IF_EMPTY_HANDLE(isolate,
1615 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001616 name,
1617 value,
1618 attributes,
1619 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 return *value;
1621 }
1622
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 // constant. For now, we determine this by checking if the
1625 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001626 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 PropertyType type = lookup.type();
1628 if (type == FIELD) {
1629 FixedArray* properties = global->properties();
1630 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001631 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 properties->set(index, *value);
1633 }
1634 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001635 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1636 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001637 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638 }
1639 } else {
1640 // Ignore re-initialization of constants that have already been
1641 // assigned a function value.
1642 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1643 }
1644
1645 // Use the set value as the result of the operation.
1646 return *value;
1647}
1648
1649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001650RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001651 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652 ASSERT(args.length() == 3);
1653
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001654 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001657 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 RUNTIME_ASSERT(args[1]->IsContext());
1659 Handle<Context> context(Context::cast(args[1])->declaration_context());
1660
1661 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662
1663 int index;
1664 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001665 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001666 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001667 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001668 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 ASSERT(holder->IsContext());
1672 // Property was found in a context. Perform the assignment if we
1673 // found some non-constant or an uninitialized constant.
1674 Handle<Context> context = Handle<Context>::cast(holder);
1675 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1676 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001677 }
1678 return *value;
1679 }
1680
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001681 // The property could not be found, we introduce it as a property of the
1682 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001683 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 Handle<JSObject> global = Handle<JSObject>(
1685 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001686 // Strict mode not needed (const disallowed in strict mode).
1687 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001689 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001690 return *value;
1691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001693 // The property was present in some function's context extension object,
1694 // as a property on the subject of a with, or as a property of the global
1695 // object.
1696 //
1697 // In most situations, eval-introduced consts should still be present in
1698 // the context extension object. However, because declaration and
1699 // initialization are separate, the property might have been deleted
1700 // before we reach the initialization point.
1701 //
1702 // Example:
1703 //
1704 // function f() { eval("delete x; const x;"); }
1705 //
1706 // In that case, the initialization behaves like a normal assignment.
1707 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001708
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001709 if (*object == context->extension()) {
1710 // This is the property that was introduced by the const declaration.
1711 // Set it if it hasn't been set before. NOTE: We cannot use
1712 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001713 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001714 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001715 ASSERT(lookup.IsProperty()); // the property was declared
1716 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1717
1718 PropertyType type = lookup.type();
1719 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001720 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001721 int index = lookup.GetFieldIndex();
1722 if (properties->get(index)->IsTheHole()) {
1723 properties->set(index, *value);
1724 }
1725 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001726 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1727 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001728 }
1729 } else {
1730 // We should not reach here. Any real, named property should be
1731 // either a field or a dictionary slot.
1732 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 }
1734 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001735 // The property was found on some other object. Set it if it is not a
1736 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001737 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001738 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001739 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001741 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001742 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001744
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 return *value;
1746}
1747
1748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001749RUNTIME_FUNCTION(MaybeObject*,
1750 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001752 ASSERT(args.length() == 2);
1753 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001754 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001755 if (object->HasFastProperties()) {
1756 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1757 }
1758 return *object;
1759}
1760
1761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001762RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001764 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001765 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1766 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001767 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001768 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001769 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001770 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001771 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001772 RUNTIME_ASSERT(index >= 0);
1773 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001774 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001775 Handle<Object> result = RegExpImpl::Exec(regexp,
1776 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001777 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001778 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001779 if (result.is_null()) return Failure::Exception();
1780 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781}
1782
1783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001784RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001785 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001786 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001787 if (elements_count < 0 ||
1788 elements_count > FixedArray::kMaxLength ||
1789 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001791 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001792 Object* new_object;
1793 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1796 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001797 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1799 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001800 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1801 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001802 {
1803 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001805 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001807 }
1808 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001810 array->set_elements(elements);
1811 array->set_length(Smi::FromInt(elements_count));
1812 // Write in-object properties after the length of the array.
1813 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1814 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1815 return array;
1816}
1817
1818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001819RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001820 AssertNoAllocation no_alloc;
1821 ASSERT(args.length() == 5);
1822 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1823 CONVERT_CHECKED(String, source, args[1]);
1824
1825 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001827
1828 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001830
1831 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001833
1834 Map* map = regexp->map();
1835 Object* constructor = map->constructor();
1836 if (constructor->IsJSFunction() &&
1837 JSFunction::cast(constructor)->initial_map() == map) {
1838 // If we still have the original map, set in-object properties directly.
1839 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1840 // TODO(lrn): Consider skipping write barrier on booleans as well.
1841 // Both true and false should be in oldspace at all times.
1842 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1843 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1844 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1845 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1846 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001847 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001848 return regexp;
1849 }
1850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001852 PropertyAttributes final =
1853 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1854 PropertyAttributes writable =
1855 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001857 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001859 source,
1860 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001861 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001863 global,
1864 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001865 ASSERT(!result->IsFailure());
1866 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001868 ignoreCase,
1869 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001870 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001872 multiline,
1873 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001874 ASSERT(!result->IsFailure());
1875 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001876 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001877 Smi::FromInt(0),
1878 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001879 ASSERT(!result->IsFailure());
1880 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001881 return regexp;
1882}
1883
1884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001885RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001886 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001887 ASSERT(args.length() == 1);
1888 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1889 // This is necessary to enable fast checks for absence of elements
1890 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001892 return Smi::FromInt(0);
1893}
1894
1895
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1897 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001898 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001899 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1901 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1902 Handle<JSFunction> optimized =
1903 isolate->factory()->NewFunction(key,
1904 JS_OBJECT_TYPE,
1905 JSObject::kHeaderSize,
1906 code,
1907 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001908 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001909 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001910 return optimized;
1911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001915 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001916 ASSERT(args.length() == 1);
1917 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1918
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001919 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1920 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1921 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1922 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1923 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1924 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1925 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001926
1927 return *holder;
1928}
1929
1930
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001931RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1932 NoHandleAllocation handle_free;
1933 ASSERT(args.length() == 1);
1934 CONVERT_CHECKED(JSFunction, function, args[0]);
1935 SharedFunctionInfo* shared = function->shared();
1936 if (shared->native() || shared->strict_mode()) {
1937 return isolate->heap()->undefined_value();
1938 }
1939 // Returns undefined for strict or native functions, or
1940 // the associated global receiver for "normal" functions.
1941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001943 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001944 return global_context->global()->global_receiver();
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 ASSERT(args.length() == 4);
1951 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001952 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 Handle<String> pattern = args.at<String>(2);
1954 Handle<String> flags = args.at<String>(3);
1955
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001956 // Get the RegExp function from the context in the literals array.
1957 // This is the RegExp function from the context in which the
1958 // function was created. We do not use the RegExp function from the
1959 // current global context because this might be the RegExp function
1960 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001961 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001962 Handle<JSFunction>(
1963 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964 // Compute the regular expression literal.
1965 bool has_pending_exception;
1966 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001967 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1968 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001971 return Failure::Exception();
1972 }
1973 literals->set(index, *regexp);
1974 return *regexp;
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, f, args[0]);
1983 return f->shared()->name();
1984}
1985
1986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001987RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001988 NoHandleAllocation ha;
1989 ASSERT(args.length() == 2);
1990
1991 CONVERT_CHECKED(JSFunction, f, args[0]);
1992 CONVERT_CHECKED(String, name, args[1]);
1993 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001995}
1996
1997
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 1);
2001 CONVERT_CHECKED(JSFunction, f, args[0]);
2002 return isolate->heap()->ToBoolean(
2003 f->shared()->name_should_print_as_anonymous());
2004}
2005
2006
2007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2008 NoHandleAllocation ha;
2009 ASSERT(args.length() == 1);
2010 CONVERT_CHECKED(JSFunction, f, args[0]);
2011 f->shared()->set_name_should_print_as_anonymous(true);
2012 return isolate->heap()->undefined_value();
2013}
2014
2015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002016RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002017 NoHandleAllocation ha;
2018 ASSERT(args.length() == 1);
2019
2020 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 Object* obj = f->RemovePrototype();
2022 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002024 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002025}
2026
2027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002028RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002029 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 ASSERT(args.length() == 1);
2031
2032 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002033 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2034 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002035
2036 return *GetScriptWrapper(Handle<Script>::cast(script));
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 NoHandleAllocation ha;
2042 ASSERT(args.length() == 1);
2043
2044 CONVERT_CHECKED(JSFunction, f, args[0]);
2045 return f->shared()->GetSourceCode();
2046}
2047
2048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050 NoHandleAllocation ha;
2051 ASSERT(args.length() == 1);
2052
2053 CONVERT_CHECKED(JSFunction, fun, args[0]);
2054 int pos = fun->shared()->start_position();
2055 return Smi::FromInt(pos);
2056}
2057
2058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002060 ASSERT(args.length() == 2);
2061
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002062 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002063 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2064
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002065 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2066
2067 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002068 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002069}
2070
2071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002072RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 NoHandleAllocation ha;
2074 ASSERT(args.length() == 2);
2075
2076 CONVERT_CHECKED(JSFunction, fun, args[0]);
2077 CONVERT_CHECKED(String, name, args[1]);
2078 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002079 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080}
2081
2082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002083RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084 NoHandleAllocation ha;
2085 ASSERT(args.length() == 2);
2086
2087 CONVERT_CHECKED(JSFunction, fun, args[0]);
2088 CONVERT_CHECKED(Smi, length, args[1]);
2089 fun->shared()->set_length(length->value());
2090 return length;
2091}
2092
2093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002094RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002095 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002096 ASSERT(args.length() == 2);
2097
2098 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002099 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002100 Object* obj;
2101 { MaybeObject* maybe_obj =
2102 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2103 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105 return args[0]; // return TOS
2106}
2107
2108
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002109RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2110 NoHandleAllocation ha;
2111 RUNTIME_ASSERT(args.length() == 1);
2112 CONVERT_CHECKED(JSFunction, function, args[0]);
2113
2114 MaybeObject* maybe_name =
2115 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2116 String* name;
2117 if (!maybe_name->To(&name)) return maybe_name;
2118
2119 if (function->HasFastProperties()) {
2120 // Construct a new field descriptor with updated attributes.
2121 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2122 int index = instance_desc->Search(name);
2123 ASSERT(index != DescriptorArray::kNotFound);
2124 PropertyDetails details(instance_desc->GetDetails(index));
2125 CallbacksDescriptor new_desc(name,
2126 instance_desc->GetValue(index),
2127 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2128 details.index());
2129 // Construct a new field descriptors array containing the new descriptor.
2130 Object* descriptors_unchecked;
2131 { MaybeObject* maybe_descriptors_unchecked =
2132 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2133 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2134 return maybe_descriptors_unchecked;
2135 }
2136 }
2137 DescriptorArray* new_descriptors =
2138 DescriptorArray::cast(descriptors_unchecked);
2139 // Create a new map featuring the new field descriptors array.
2140 Object* map_unchecked;
2141 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2142 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2143 return maybe_map_unchecked;
2144 }
2145 }
2146 Map* new_map = Map::cast(map_unchecked);
2147 new_map->set_instance_descriptors(new_descriptors);
2148 function->set_map(new_map);
2149 } else { // Dictionary properties.
2150 // Directly manipulate the property details.
2151 int entry = function->property_dictionary()->FindEntry(name);
2152 ASSERT(entry != StringDictionary::kNotFound);
2153 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2154 PropertyDetails new_details(
2155 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2156 details.type(),
2157 details.index());
2158 function->property_dictionary()->DetailsAtPut(entry, new_details);
2159 }
2160 return function;
2161}
2162
2163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002164RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002165 NoHandleAllocation ha;
2166 ASSERT(args.length() == 1);
2167
2168 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002169 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002170}
2171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002173RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002174 NoHandleAllocation ha;
2175 ASSERT(args.length() == 1);
2176
2177 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002178 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002179}
2180
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002182RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 ASSERT(args.length() == 2);
2185
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002186 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187 Handle<Object> code = args.at<Object>(1);
2188
2189 Handle<Context> context(target->context());
2190
2191 if (!code->IsNull()) {
2192 RUNTIME_ASSERT(code->IsJSFunction());
2193 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002194 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002196 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 return Failure::Exception();
2198 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002199 // Since we don't store the source for this we should never
2200 // optimize this.
2201 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002202 // Set the code, scope info, formal parameter count,
2203 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002204 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002205 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002206 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002207 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002210 // Set the source code of the target function to undefined.
2211 // SetCode is only used for built-in constructors like String,
2212 // Array, and Object, and some web code
2213 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002215 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002216 // Clear the optimization hints related to the compiled code as these are no
2217 // longer valid when the code is overwritten.
2218 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219 context = Handle<Context>(fun->context());
2220
2221 // Make sure we get a fresh copy of the literal vector to avoid
2222 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002223 int number_of_literals = fun->NumberOfLiterals();
2224 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002226 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002227 // Insert the object, regexp and array functions in the literals
2228 // array prefix. These are the functions that will be used when
2229 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002230 literals->set(JSFunction::kLiteralGlobalContextIndex,
2231 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002232 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002233 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002235
2236 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2237 isolate->logger()->LogExistingFunction(
2238 shared, Handle<Code>(shared->code()));
2239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240 }
2241
2242 target->set_context(*context);
2243 return *target;
2244}
2245
2246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002247RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002248 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002249 ASSERT(args.length() == 2);
2250 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002251 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002252 RUNTIME_ASSERT(num >= 0);
2253 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002255}
2256
2257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002258MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2259 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002260 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002261 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002262 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002263 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002264 }
2265 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002266 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002267}
2268
2269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002270RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 NoHandleAllocation ha;
2272 ASSERT(args.length() == 2);
2273
2274 CONVERT_CHECKED(String, subject, args[0]);
2275 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002277
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002278 uint32_t i = 0;
2279 if (index->IsSmi()) {
2280 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002281 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002282 i = value;
2283 } else {
2284 ASSERT(index->IsHeapNumber());
2285 double value = HeapNumber::cast(index)->value();
2286 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002287 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002288
2289 // Flatten the string. If someone wants to get a char at an index
2290 // in a cons string, it is likely that more indices will be
2291 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002292 Object* flat;
2293 { MaybeObject* maybe_flat = subject->TryFlatten();
2294 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2295 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002296 subject = String::cast(flat);
2297
2298 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002299 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002300 }
2301
2302 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002303}
2304
2305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002306RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002307 NoHandleAllocation ha;
2308 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002309 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002310}
2311
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312
2313class FixedArrayBuilder {
2314 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2316 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002317 length_(0),
2318 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 // Require a non-zero initial size. Ensures that doubling the size to
2320 // extend the array will work.
2321 ASSERT(initial_capacity > 0);
2322 }
2323
2324 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2325 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 length_(0),
2327 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 // Require a non-zero initial size. Ensures that doubling the size to
2329 // extend the array will work.
2330 ASSERT(backing_store->length() > 0);
2331 }
2332
2333 bool HasCapacity(int elements) {
2334 int length = array_->length();
2335 int required_length = length_ + elements;
2336 return (length >= required_length);
2337 }
2338
2339 void EnsureCapacity(int elements) {
2340 int length = array_->length();
2341 int required_length = length_ + elements;
2342 if (length < required_length) {
2343 int new_length = length;
2344 do {
2345 new_length *= 2;
2346 } while (new_length < required_length);
2347 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002348 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002349 array_->CopyTo(0, *extended_array, 0, length_);
2350 array_ = extended_array;
2351 }
2352 }
2353
2354 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002355 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356 ASSERT(length_ < capacity());
2357 array_->set(length_, value);
2358 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360 }
2361
2362 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002363 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002364 ASSERT(length_ < capacity());
2365 array_->set(length_, value);
2366 length_++;
2367 }
2368
2369 Handle<FixedArray> array() {
2370 return array_;
2371 }
2372
2373 int length() {
2374 return length_;
2375 }
2376
2377 int capacity() {
2378 return array_->length();
2379 }
2380
2381 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002382 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 result_array->set_length(Smi::FromInt(length_));
2384 return result_array;
2385 }
2386
2387 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002388 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 target_array->set_length(Smi::FromInt(length_));
2390 return target_array;
2391 }
2392
2393 private:
2394 Handle<FixedArray> array_;
2395 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002396 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397};
2398
2399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002401const int kStringBuilderConcatHelperLengthBits = 11;
2402const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403
2404template <typename schar>
2405static inline void StringBuilderConcatHelper(String*,
2406 schar*,
2407 FixedArray*,
2408 int);
2409
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2411 StringBuilderSubstringLength;
2412typedef BitField<int,
2413 kStringBuilderConcatHelperLengthBits,
2414 kStringBuilderConcatHelperPositionBits>
2415 StringBuilderSubstringPosition;
2416
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417
2418class ReplacementStringBuilder {
2419 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002420 ReplacementStringBuilder(Heap* heap,
2421 Handle<String> subject,
2422 int estimated_part_count)
2423 : heap_(heap),
2424 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002425 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002426 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002427 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 // Require a non-zero initial size. Ensures that doubling the size to
2429 // extend the array will work.
2430 ASSERT(estimated_part_count > 0);
2431 }
2432
lrn@chromium.org25156de2010-04-06 13:10:27 +00002433 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2434 int from,
2435 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002436 ASSERT(from >= 0);
2437 int length = to - from;
2438 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 if (StringBuilderSubstringLength::is_valid(length) &&
2440 StringBuilderSubstringPosition::is_valid(from)) {
2441 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2442 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002443 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002445 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 builder->Add(Smi::FromInt(-length));
2447 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 }
2450
2451
2452 void EnsureCapacity(int elements) {
2453 array_builder_.EnsureCapacity(elements);
2454 }
2455
2456
2457 void AddSubjectSlice(int from, int to) {
2458 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 }
2461
2462
2463 void AddString(Handle<String> string) {
2464 int length = string->length();
2465 ASSERT(length > 0);
2466 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002467 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 is_ascii_ = false;
2469 }
2470 IncrementCharacterCount(length);
2471 }
2472
2473
2474 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002475 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002476 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 }
2478
2479 Handle<String> joined_string;
2480 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002481 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002483 char* char_buffer = seq->GetChars();
2484 StringBuilderConcatHelper(*subject_,
2485 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 *array_builder_.array(),
2487 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002488 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 } else {
2490 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002491 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002492 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 uc16* char_buffer = seq->GetChars();
2494 StringBuilderConcatHelper(*subject_,
2495 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002496 *array_builder_.array(),
2497 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002498 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 }
2500 return joined_string;
2501 }
2502
2503
2504 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002505 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 V8::FatalProcessOutOfMemory("String.replace result too large.");
2507 }
2508 character_count_ += by;
2509 }
2510
lrn@chromium.org25156de2010-04-06 13:10:27 +00002511 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002512 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002513 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002514
lrn@chromium.org25156de2010-04-06 13:10:27 +00002515 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002516 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2517 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002518 }
2519
2520
ager@chromium.org04921a82011-06-27 13:21:41 +00002521 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2522 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 }
2524
2525
2526 void AddElement(Object* element) {
2527 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002528 ASSERT(array_builder_.capacity() > array_builder_.length());
2529 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002530 }
2531
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002532 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002533 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002535 int character_count_;
2536 bool is_ascii_;
2537};
2538
2539
2540class CompiledReplacement {
2541 public:
2542 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002543 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002544
2545 void Compile(Handle<String> replacement,
2546 int capture_count,
2547 int subject_length);
2548
2549 void Apply(ReplacementStringBuilder* builder,
2550 int match_from,
2551 int match_to,
2552 Handle<JSArray> last_match_info);
2553
2554 // Number of distinct parts of the replacement pattern.
2555 int parts() {
2556 return parts_.length();
2557 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002558
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002559 bool simple_hint() {
2560 return simple_hint_;
2561 }
2562
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002563 private:
2564 enum PartType {
2565 SUBJECT_PREFIX = 1,
2566 SUBJECT_SUFFIX,
2567 SUBJECT_CAPTURE,
2568 REPLACEMENT_SUBSTRING,
2569 REPLACEMENT_STRING,
2570
2571 NUMBER_OF_PART_TYPES
2572 };
2573
2574 struct ReplacementPart {
2575 static inline ReplacementPart SubjectMatch() {
2576 return ReplacementPart(SUBJECT_CAPTURE, 0);
2577 }
2578 static inline ReplacementPart SubjectCapture(int capture_index) {
2579 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2580 }
2581 static inline ReplacementPart SubjectPrefix() {
2582 return ReplacementPart(SUBJECT_PREFIX, 0);
2583 }
2584 static inline ReplacementPart SubjectSuffix(int subject_length) {
2585 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2586 }
2587 static inline ReplacementPart ReplacementString() {
2588 return ReplacementPart(REPLACEMENT_STRING, 0);
2589 }
2590 static inline ReplacementPart ReplacementSubString(int from, int to) {
2591 ASSERT(from >= 0);
2592 ASSERT(to > from);
2593 return ReplacementPart(-from, to);
2594 }
2595
2596 // If tag <= 0 then it is the negation of a start index of a substring of
2597 // the replacement pattern, otherwise it's a value from PartType.
2598 ReplacementPart(int tag, int data)
2599 : tag(tag), data(data) {
2600 // Must be non-positive or a PartType value.
2601 ASSERT(tag < NUMBER_OF_PART_TYPES);
2602 }
2603 // Either a value of PartType or a non-positive number that is
2604 // the negation of an index into the replacement string.
2605 int tag;
2606 // The data value's interpretation depends on the value of tag:
2607 // tag == SUBJECT_PREFIX ||
2608 // tag == SUBJECT_SUFFIX: data is unused.
2609 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2610 // tag == REPLACEMENT_SUBSTRING ||
2611 // tag == REPLACEMENT_STRING: data is index into array of substrings
2612 // of the replacement string.
2613 // tag <= 0: Temporary representation of the substring of the replacement
2614 // string ranging over -tag .. data.
2615 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2616 // substring objects.
2617 int data;
2618 };
2619
2620 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002621 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002622 Vector<Char> characters,
2623 int capture_count,
2624 int subject_length) {
2625 int length = characters.length();
2626 int last = 0;
2627 for (int i = 0; i < length; i++) {
2628 Char c = characters[i];
2629 if (c == '$') {
2630 int next_index = i + 1;
2631 if (next_index == length) { // No next character!
2632 break;
2633 }
2634 Char c2 = characters[next_index];
2635 switch (c2) {
2636 case '$':
2637 if (i > last) {
2638 // There is a substring before. Include the first "$".
2639 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2640 last = next_index + 1; // Continue after the second "$".
2641 } else {
2642 // Let the next substring start with the second "$".
2643 last = next_index;
2644 }
2645 i = next_index;
2646 break;
2647 case '`':
2648 if (i > last) {
2649 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2650 }
2651 parts->Add(ReplacementPart::SubjectPrefix());
2652 i = next_index;
2653 last = i + 1;
2654 break;
2655 case '\'':
2656 if (i > last) {
2657 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2658 }
2659 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2660 i = next_index;
2661 last = i + 1;
2662 break;
2663 case '&':
2664 if (i > last) {
2665 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2666 }
2667 parts->Add(ReplacementPart::SubjectMatch());
2668 i = next_index;
2669 last = i + 1;
2670 break;
2671 case '0':
2672 case '1':
2673 case '2':
2674 case '3':
2675 case '4':
2676 case '5':
2677 case '6':
2678 case '7':
2679 case '8':
2680 case '9': {
2681 int capture_ref = c2 - '0';
2682 if (capture_ref > capture_count) {
2683 i = next_index;
2684 continue;
2685 }
2686 int second_digit_index = next_index + 1;
2687 if (second_digit_index < length) {
2688 // Peek ahead to see if we have two digits.
2689 Char c3 = characters[second_digit_index];
2690 if ('0' <= c3 && c3 <= '9') { // Double digits.
2691 int double_digit_ref = capture_ref * 10 + c3 - '0';
2692 if (double_digit_ref <= capture_count) {
2693 next_index = second_digit_index;
2694 capture_ref = double_digit_ref;
2695 }
2696 }
2697 }
2698 if (capture_ref > 0) {
2699 if (i > last) {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2701 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002702 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2704 last = next_index + 1;
2705 }
2706 i = next_index;
2707 break;
2708 }
2709 default:
2710 i = next_index;
2711 break;
2712 }
2713 }
2714 }
2715 if (length > last) {
2716 if (last == 0) {
2717 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002718 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002719 } else {
2720 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2721 }
2722 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002723 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 }
2725
2726 ZoneList<ReplacementPart> parts_;
2727 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002728 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729};
2730
2731
2732void CompiledReplacement::Compile(Handle<String> replacement,
2733 int capture_count,
2734 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002735 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002736 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002737 String::FlatContent content = replacement->GetFlatContent();
2738 ASSERT(content.IsFlat());
2739 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002740 simple_hint_ = ParseReplacementPattern(&parts_,
2741 content.ToAsciiVector(),
2742 capture_count,
2743 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002744 } else {
2745 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002746 simple_hint_ = ParseReplacementPattern(&parts_,
2747 content.ToUC16Vector(),
2748 capture_count,
2749 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002750 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002751 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002753 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002754 int substring_index = 0;
2755 for (int i = 0, n = parts_.length(); i < n; i++) {
2756 int tag = parts_[i].tag;
2757 if (tag <= 0) { // A replacement string slice.
2758 int from = -tag;
2759 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002760 replacement_substrings_.Add(
2761 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002762 parts_[i].tag = REPLACEMENT_SUBSTRING;
2763 parts_[i].data = substring_index;
2764 substring_index++;
2765 } else if (tag == REPLACEMENT_STRING) {
2766 replacement_substrings_.Add(replacement);
2767 parts_[i].data = substring_index;
2768 substring_index++;
2769 }
2770 }
2771}
2772
2773
2774void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2775 int match_from,
2776 int match_to,
2777 Handle<JSArray> last_match_info) {
2778 for (int i = 0, n = parts_.length(); i < n; i++) {
2779 ReplacementPart part = parts_[i];
2780 switch (part.tag) {
2781 case SUBJECT_PREFIX:
2782 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2783 break;
2784 case SUBJECT_SUFFIX: {
2785 int subject_length = part.data;
2786 if (match_to < subject_length) {
2787 builder->AddSubjectSlice(match_to, subject_length);
2788 }
2789 break;
2790 }
2791 case SUBJECT_CAPTURE: {
2792 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002793 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002794 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2795 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2796 if (from >= 0 && to > from) {
2797 builder->AddSubjectSlice(from, to);
2798 }
2799 break;
2800 }
2801 case REPLACEMENT_SUBSTRING:
2802 case REPLACEMENT_STRING:
2803 builder->AddString(replacement_substrings_[part.data]);
2804 break;
2805 default:
2806 UNREACHABLE();
2807 }
2808 }
2809}
2810
2811
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002812void FindAsciiStringIndices(Vector<const char> subject,
2813 char pattern,
2814 ZoneList<int>* indices,
2815 unsigned int limit) {
2816 ASSERT(limit > 0);
2817 // Collect indices of pattern in subject using memchr.
2818 // Stop after finding at most limit values.
2819 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2820 const char* subject_end = subject_start + subject.length();
2821 const char* pos = subject_start;
2822 while (limit > 0) {
2823 pos = reinterpret_cast<const char*>(
2824 memchr(pos, pattern, subject_end - pos));
2825 if (pos == NULL) return;
2826 indices->Add(static_cast<int>(pos - subject_start));
2827 pos++;
2828 limit--;
2829 }
2830}
2831
2832
2833template <typename SubjectChar, typename PatternChar>
2834void FindStringIndices(Isolate* isolate,
2835 Vector<const SubjectChar> subject,
2836 Vector<const PatternChar> pattern,
2837 ZoneList<int>* indices,
2838 unsigned int limit) {
2839 ASSERT(limit > 0);
2840 // Collect indices of pattern in subject.
2841 // Stop after finding at most limit values.
2842 int pattern_length = pattern.length();
2843 int index = 0;
2844 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2845 while (limit > 0) {
2846 index = search.Search(subject, index);
2847 if (index < 0) return;
2848 indices->Add(index);
2849 index += pattern_length;
2850 limit--;
2851 }
2852}
2853
2854
2855void FindStringIndicesDispatch(Isolate* isolate,
2856 String* subject,
2857 String* pattern,
2858 ZoneList<int>* indices,
2859 unsigned int limit) {
2860 {
2861 AssertNoAllocation no_gc;
2862 String::FlatContent subject_content = subject->GetFlatContent();
2863 String::FlatContent pattern_content = pattern->GetFlatContent();
2864 ASSERT(subject_content.IsFlat());
2865 ASSERT(pattern_content.IsFlat());
2866 if (subject_content.IsAscii()) {
2867 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2868 if (pattern_content.IsAscii()) {
2869 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2870 if (pattern_vector.length() == 1) {
2871 FindAsciiStringIndices(subject_vector,
2872 pattern_vector[0],
2873 indices,
2874 limit);
2875 } else {
2876 FindStringIndices(isolate,
2877 subject_vector,
2878 pattern_vector,
2879 indices,
2880 limit);
2881 }
2882 } else {
2883 FindStringIndices(isolate,
2884 subject_vector,
2885 pattern_content.ToUC16Vector(),
2886 indices,
2887 limit);
2888 }
2889 } else {
2890 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002891 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002892 FindStringIndices(isolate,
2893 subject_vector,
2894 pattern_content.ToAsciiVector(),
2895 indices,
2896 limit);
2897 } else {
2898 FindStringIndices(isolate,
2899 subject_vector,
2900 pattern_content.ToUC16Vector(),
2901 indices,
2902 limit);
2903 }
2904 }
2905 }
2906}
2907
2908
2909template<typename ResultSeqString>
2910MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2911 Isolate* isolate,
2912 Handle<String> subject,
2913 Handle<JSRegExp> pattern_regexp,
2914 Handle<String> replacement) {
2915 ASSERT(subject->IsFlat());
2916 ASSERT(replacement->IsFlat());
2917
2918 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2919 ZoneList<int> indices(8);
2920 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2921 String* pattern =
2922 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2923 int subject_len = subject->length();
2924 int pattern_len = pattern->length();
2925 int replacement_len = replacement->length();
2926
2927 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2928
2929 int matches = indices.length();
2930 if (matches == 0) return *subject;
2931
2932 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2933 int subject_pos = 0;
2934 int result_pos = 0;
2935
2936 Handle<ResultSeqString> result;
2937 if (ResultSeqString::kHasAsciiEncoding) {
2938 result = Handle<ResultSeqString>::cast(
2939 isolate->factory()->NewRawAsciiString(result_len));
2940 } else {
2941 result = Handle<ResultSeqString>::cast(
2942 isolate->factory()->NewRawTwoByteString(result_len));
2943 }
2944
2945 for (int i = 0; i < matches; i++) {
2946 // Copy non-matched subject content.
2947 if (subject_pos < indices.at(i)) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 indices.at(i));
2952 result_pos += indices.at(i) - subject_pos;
2953 }
2954
2955 // Replace match.
2956 if (replacement_len > 0) {
2957 String::WriteToFlat(*replacement,
2958 result->GetChars() + result_pos,
2959 0,
2960 replacement_len);
2961 result_pos += replacement_len;
2962 }
2963
2964 subject_pos = indices.at(i) + pattern_len;
2965 }
2966 // Add remaining subject content at the end.
2967 if (subject_pos < subject_len) {
2968 String::WriteToFlat(*subject,
2969 result->GetChars() + result_pos,
2970 subject_pos,
2971 subject_len);
2972 }
2973 return *result;
2974}
2975
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002976
lrn@chromium.org303ada72010-10-27 09:33:13 +00002977MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002978 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002979 String* subject,
2980 JSRegExp* regexp,
2981 String* replacement,
2982 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002983 ASSERT(subject->IsFlat());
2984 ASSERT(replacement->IsFlat());
2985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002986 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002987
2988 int length = subject->length();
2989 Handle<String> subject_handle(subject);
2990 Handle<JSRegExp> regexp_handle(regexp);
2991 Handle<String> replacement_handle(replacement);
2992 Handle<JSArray> last_match_info_handle(last_match_info);
2993 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2994 subject_handle,
2995 0,
2996 last_match_info_handle);
2997 if (match.is_null()) {
2998 return Failure::Exception();
2999 }
3000 if (match->IsNull()) {
3001 return *subject_handle;
3002 }
3003
3004 int capture_count = regexp_handle->CaptureCount();
3005
3006 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003007 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008 CompiledReplacement compiled_replacement;
3009 compiled_replacement.Compile(replacement_handle,
3010 capture_count,
3011 length);
3012
3013 bool is_global = regexp_handle->GetFlags().is_global();
3014
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003015 // Shortcut for simple non-regexp global replacements
3016 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003017 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003018 compiled_replacement.simple_hint()) {
3019 if (subject_handle->HasOnlyAsciiChars() &&
3020 replacement_handle->HasOnlyAsciiChars()) {
3021 return StringReplaceStringWithString<SeqAsciiString>(
3022 isolate, subject_handle, regexp_handle, replacement_handle);
3023 } else {
3024 return StringReplaceStringWithString<SeqTwoByteString>(
3025 isolate, subject_handle, regexp_handle, replacement_handle);
3026 }
3027 }
3028
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029 // Guessing the number of parts that the final result string is built
3030 // from. Global regexps can match any number of times, so we guess
3031 // conservatively.
3032 int expected_parts =
3033 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034 ReplacementStringBuilder builder(isolate->heap(),
3035 subject_handle,
3036 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003037
3038 // Index of end of last match.
3039 int prev = 0;
3040
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003041 // Number of parts added by compiled replacement plus preceeding
3042 // string and possibly suffix after last match. It is possible for
3043 // all components to use two elements when encoded as two smis.
3044 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003045 bool matched = true;
3046 do {
3047 ASSERT(last_match_info_handle->HasFastElements());
3048 // Increase the capacity of the builder before entering local handle-scope,
3049 // so its internal buffer can safely allocate a new handle if it grows.
3050 builder.EnsureCapacity(parts_added_per_loop);
3051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003052 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003053 int start, end;
3054 {
3055 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003056 FixedArray* match_info_array =
3057 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003058
3059 ASSERT_EQ(capture_count * 2 + 2,
3060 RegExpImpl::GetLastCaptureCount(match_info_array));
3061 start = RegExpImpl::GetCapture(match_info_array, 0);
3062 end = RegExpImpl::GetCapture(match_info_array, 1);
3063 }
3064
3065 if (prev < start) {
3066 builder.AddSubjectSlice(prev, start);
3067 }
3068 compiled_replacement.Apply(&builder,
3069 start,
3070 end,
3071 last_match_info_handle);
3072 prev = end;
3073
3074 // Only continue checking for global regexps.
3075 if (!is_global) break;
3076
3077 // Continue from where the match ended, unless it was an empty match.
3078 int next = end;
3079 if (start == end) {
3080 next = end + 1;
3081 if (next > length) break;
3082 }
3083
3084 match = RegExpImpl::Exec(regexp_handle,
3085 subject_handle,
3086 next,
3087 last_match_info_handle);
3088 if (match.is_null()) {
3089 return Failure::Exception();
3090 }
3091 matched = !match->IsNull();
3092 } while (matched);
3093
3094 if (prev < length) {
3095 builder.AddSubjectSlice(prev, length);
3096 }
3097
3098 return *(builder.ToString());
3099}
3100
3101
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003103MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003104 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003105 String* subject,
3106 JSRegExp* regexp,
3107 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 ASSERT(subject->IsFlat());
3109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003110 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003111
3112 Handle<String> subject_handle(subject);
3113 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003114
3115 // Shortcut for simple non-regexp global replacements
3116 if (regexp_handle->GetFlags().is_global() &&
3117 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3118 Handle<String> empty_string_handle(HEAP->empty_string());
3119 if (subject_handle->HasOnlyAsciiChars()) {
3120 return StringReplaceStringWithString<SeqAsciiString>(
3121 isolate, subject_handle, regexp_handle, empty_string_handle);
3122 } else {
3123 return StringReplaceStringWithString<SeqTwoByteString>(
3124 isolate, subject_handle, regexp_handle, empty_string_handle);
3125 }
3126 }
3127
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 Handle<JSArray> last_match_info_handle(last_match_info);
3129 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3130 subject_handle,
3131 0,
3132 last_match_info_handle);
3133 if (match.is_null()) return Failure::Exception();
3134 if (match->IsNull()) return *subject_handle;
3135
3136 ASSERT(last_match_info_handle->HasFastElements());
3137
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003138 int start, end;
3139 {
3140 AssertNoAllocation match_info_array_is_not_in_a_handle;
3141 FixedArray* match_info_array =
3142 FixedArray::cast(last_match_info_handle->elements());
3143
3144 start = RegExpImpl::GetCapture(match_info_array, 0);
3145 end = RegExpImpl::GetCapture(match_info_array, 1);
3146 }
3147
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003148 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003149 int new_length = length - (end - start);
3150 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003152 }
3153 Handle<ResultSeqString> answer;
3154 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003155 answer = Handle<ResultSeqString>::cast(
3156 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003157 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003158 answer = Handle<ResultSeqString>::cast(
3159 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003160 }
3161
3162 // If the regexp isn't global, only match once.
3163 if (!regexp_handle->GetFlags().is_global()) {
3164 if (start > 0) {
3165 String::WriteToFlat(*subject_handle,
3166 answer->GetChars(),
3167 0,
3168 start);
3169 }
3170 if (end < length) {
3171 String::WriteToFlat(*subject_handle,
3172 answer->GetChars() + start,
3173 end,
3174 length);
3175 }
3176 return *answer;
3177 }
3178
3179 int prev = 0; // Index of end of last match.
3180 int next = 0; // Start of next search (prev unless last match was empty).
3181 int position = 0;
3182
3183 do {
3184 if (prev < start) {
3185 // Add substring subject[prev;start] to answer string.
3186 String::WriteToFlat(*subject_handle,
3187 answer->GetChars() + position,
3188 prev,
3189 start);
3190 position += start - prev;
3191 }
3192 prev = end;
3193 next = end;
3194 // Continue from where the match ended, unless it was an empty match.
3195 if (start == end) {
3196 next++;
3197 if (next > length) break;
3198 }
3199 match = RegExpImpl::Exec(regexp_handle,
3200 subject_handle,
3201 next,
3202 last_match_info_handle);
3203 if (match.is_null()) return Failure::Exception();
3204 if (match->IsNull()) break;
3205
3206 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208 {
3209 AssertNoAllocation match_info_array_is_not_in_a_handle;
3210 FixedArray* match_info_array =
3211 FixedArray::cast(last_match_info_handle->elements());
3212 start = RegExpImpl::GetCapture(match_info_array, 0);
3213 end = RegExpImpl::GetCapture(match_info_array, 1);
3214 }
3215 } while (true);
3216
3217 if (prev < length) {
3218 // Add substring subject[prev;length] to answer string.
3219 String::WriteToFlat(*subject_handle,
3220 answer->GetChars() + position,
3221 prev,
3222 length);
3223 position += length - prev;
3224 }
3225
3226 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003227 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 }
3229
3230 // Shorten string and fill
3231 int string_size = ResultSeqString::SizeFor(position);
3232 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3233 int delta = allocated_string_size - string_size;
3234
3235 answer->set_length(position);
3236 if (delta == 0) return *answer;
3237
3238 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003240 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3241 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3242 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003243
3244 return *answer;
3245}
3246
3247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003248RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 ASSERT(args.length() == 4);
3250
3251 CONVERT_CHECKED(String, subject, args[0]);
3252 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003253 Object* flat_subject;
3254 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3255 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3256 return maybe_flat_subject;
3257 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003258 }
3259 subject = String::cast(flat_subject);
3260 }
3261
3262 CONVERT_CHECKED(String, replacement, args[2]);
3263 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003264 Object* flat_replacement;
3265 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3266 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3267 return maybe_flat_replacement;
3268 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003269 }
3270 replacement = String::cast(flat_replacement);
3271 }
3272
3273 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3274 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3275
3276 ASSERT(last_match_info->HasFastElements());
3277
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003278 if (replacement->length() == 0) {
3279 if (subject->HasOnlyAsciiChars()) {
3280 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003282 } else {
3283 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003285 }
3286 }
3287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 return StringReplaceRegExpWithString(isolate,
3289 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003290 regexp,
3291 replacement,
3292 last_match_info);
3293}
3294
3295
ager@chromium.org7c537e22008-10-16 08:43:32 +00003296// Perform string match of pattern on subject, starting at start index.
3297// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003298// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003299int Runtime::StringMatch(Isolate* isolate,
3300 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003301 Handle<String> pat,
3302 int start_index) {
3303 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003304 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003305
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003306 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003307 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003309 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003310 if (start_index + pattern_length > subject_length) return -1;
3311
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003312 if (!sub->IsFlat()) FlattenString(sub);
3313 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003314
ager@chromium.org7c537e22008-10-16 08:43:32 +00003315 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003316 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003317 String::FlatContent seq_sub = sub->GetFlatContent();
3318 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003319
ager@chromium.org7c537e22008-10-16 08:43:32 +00003320 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003321 if (seq_pat.IsAscii()) {
3322 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3323 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003324 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003325 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003326 pat_vector,
3327 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003328 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003329 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003330 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003331 pat_vector,
3332 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003333 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003334 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3335 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003336 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003337 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 pat_vector,
3339 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003341 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003342 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343 pat_vector,
3344 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003345}
3346
3347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003348RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003350 ASSERT(args.length() == 3);
3351
ager@chromium.org7c537e22008-10-16 08:43:32 +00003352 CONVERT_ARG_CHECKED(String, sub, 0);
3353 CONVERT_ARG_CHECKED(String, pat, 1);
3354
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003355 Object* index = args[2];
3356 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003357 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003358
ager@chromium.org870a0b62008-11-04 11:43:05 +00003359 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003360 int position =
3361 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003362 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363}
3364
3365
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003366template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003367static int StringMatchBackwards(Vector<const schar> subject,
3368 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003369 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003370 int pattern_length = pattern.length();
3371 ASSERT(pattern_length >= 1);
3372 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003373
3374 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003375 for (int i = 0; i < pattern_length; i++) {
3376 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003377 if (c > String::kMaxAsciiCharCode) {
3378 return -1;
3379 }
3380 }
3381 }
3382
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003383 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003384 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003385 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003387 while (j < pattern_length) {
3388 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003389 break;
3390 }
3391 j++;
3392 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003393 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003394 return i;
3395 }
3396 }
3397 return -1;
3398}
3399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003400RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003401 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402 ASSERT(args.length() == 3);
3403
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003404 CONVERT_ARG_CHECKED(String, sub, 0);
3405 CONVERT_ARG_CHECKED(String, pat, 1);
3406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003409 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003411 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003412 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003413
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003414 if (start_index + pat_length > sub_length) {
3415 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003418 if (pat_length == 0) {
3419 return Smi::FromInt(start_index);
3420 }
3421
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003422 if (!sub->IsFlat()) FlattenString(sub);
3423 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003424
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003425 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3427
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003428 String::FlatContent sub_content = sub->GetFlatContent();
3429 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003431 if (pat_content.IsAscii()) {
3432 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3433 if (sub_content.IsAscii()) {
3434 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003435 pat_vector,
3436 start_index);
3437 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003438 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 pat_vector,
3440 start_index);
3441 }
3442 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003443 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3444 if (sub_content.IsAscii()) {
3445 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003446 pat_vector,
3447 start_index);
3448 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003449 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450 pat_vector,
3451 start_index);
3452 }
3453 }
3454
3455 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456}
3457
3458
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003459RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 NoHandleAllocation ha;
3461 ASSERT(args.length() == 2);
3462
3463 CONVERT_CHECKED(String, str1, args[0]);
3464 CONVERT_CHECKED(String, str2, args[1]);
3465
3466 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003467 int str1_length = str1->length();
3468 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003469
3470 // Decide trivial cases without flattening.
3471 if (str1_length == 0) {
3472 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3473 return Smi::FromInt(-str2_length);
3474 } else {
3475 if (str2_length == 0) return Smi::FromInt(str1_length);
3476 }
3477
3478 int end = str1_length < str2_length ? str1_length : str2_length;
3479
3480 // No need to flatten if we are going to find the answer on the first
3481 // character. At this point we know there is at least one character
3482 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003483 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484 if (d != 0) return Smi::FromInt(d);
3485
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003486 str1->TryFlatten();
3487 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003489 StringInputBuffer& buf1 =
3490 *isolate->runtime_state()->string_locale_compare_buf1();
3491 StringInputBuffer& buf2 =
3492 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493
3494 buf1.Reset(str1);
3495 buf2.Reset(str2);
3496
3497 for (int i = 0; i < end; i++) {
3498 uint16_t char1 = buf1.GetNext();
3499 uint16_t char2 = buf2.GetNext();
3500 if (char1 != char2) return Smi::FromInt(char1 - char2);
3501 }
3502
3503 return Smi::FromInt(str1_length - str2_length);
3504}
3505
3506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003507RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003508 NoHandleAllocation ha;
3509 ASSERT(args.length() == 3);
3510
3511 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003512 int start, end;
3513 // We have a fast integer-only case here to avoid a conversion to double in
3514 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003515 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3516 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3517 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3518 start = from_number;
3519 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003520 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003521 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3522 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003523 start = FastD2I(from_number);
3524 end = FastD2I(to_number);
3525 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526 RUNTIME_ASSERT(end >= start);
3527 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003528 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003530 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531}
3532
3533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003534RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003535 ASSERT_EQ(3, args.length());
3536
3537 CONVERT_ARG_CHECKED(String, subject, 0);
3538 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3539 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3540 HandleScope handles;
3541
3542 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3543
3544 if (match.is_null()) {
3545 return Failure::Exception();
3546 }
3547 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003548 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003549 }
3550 int length = subject->length();
3551
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003552 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003553 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003554 int start;
3555 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003556 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003557 {
3558 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003559 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003560 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3561 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3562 }
3563 offsets.Add(start);
3564 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003565 if (start == end) if (++end > length) break;
3566 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003567 if (match.is_null()) {
3568 return Failure::Exception();
3569 }
3570 } while (!match->IsNull());
3571 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003573 Handle<String> substring = isolate->factory()->
3574 NewSubString(subject, offsets.at(0), offsets.at(1));
3575 elements->set(0, *substring);
3576 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003577 int from = offsets.at(i * 2);
3578 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003579 Handle<String> substring = isolate->factory()->
3580 NewProperSubString(subject, from, to);
3581 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003582 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 result->set_length(Smi::FromInt(matches));
3585 return *result;
3586}
3587
3588
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589// Two smis before and after the match, for very long strings.
3590const int kMaxBuilderEntriesPerRegExpMatch = 5;
3591
3592
3593static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3594 Handle<JSArray> last_match_info,
3595 int match_start,
3596 int match_end) {
3597 // Fill last_match_info with a single capture.
3598 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3599 AssertNoAllocation no_gc;
3600 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3601 RegExpImpl::SetLastCaptureCount(elements, 2);
3602 RegExpImpl::SetLastInput(elements, *subject);
3603 RegExpImpl::SetLastSubject(elements, *subject);
3604 RegExpImpl::SetCapture(elements, 0, match_start);
3605 RegExpImpl::SetCapture(elements, 1, match_end);
3606}
3607
3608
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003609template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610static bool SearchStringMultiple(Isolate* isolate,
3611 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003612 Vector<const PatternChar> pattern,
3613 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003614 FixedArrayBuilder* builder,
3615 int* match_pos) {
3616 int pos = *match_pos;
3617 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003618 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003619 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003621 while (pos <= max_search_start) {
3622 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3623 *match_pos = pos;
3624 return false;
3625 }
3626 // Position of end of previous match.
3627 int match_end = pos + pattern_length;
3628 int new_pos = search.Search(subject, match_end);
3629 if (new_pos >= 0) {
3630 // A match.
3631 if (new_pos > match_end) {
3632 ReplacementStringBuilder::AddSubjectSlice(builder,
3633 match_end,
3634 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003635 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003636 pos = new_pos;
3637 builder->Add(pattern_string);
3638 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003640 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003641 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003642
lrn@chromium.org25156de2010-04-06 13:10:27 +00003643 if (pos < max_search_start) {
3644 ReplacementStringBuilder::AddSubjectSlice(builder,
3645 pos + pattern_length,
3646 subject_length);
3647 }
3648 *match_pos = pos;
3649 return true;
3650}
3651
3652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653static bool SearchStringMultiple(Isolate* isolate,
3654 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003655 Handle<String> pattern,
3656 Handle<JSArray> last_match_info,
3657 FixedArrayBuilder* builder) {
3658 ASSERT(subject->IsFlat());
3659 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660
3661 // Treating as if a previous match was before first character.
3662 int match_pos = -pattern->length();
3663
3664 for (;;) { // Break when search complete.
3665 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3666 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003667 String::FlatContent subject_content = subject->GetFlatContent();
3668 String::FlatContent pattern_content = pattern->GetFlatContent();
3669 if (subject_content.IsAscii()) {
3670 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3671 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003672 if (SearchStringMultiple(isolate,
3673 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003674 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003675 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003676 builder,
3677 &match_pos)) break;
3678 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003679 if (SearchStringMultiple(isolate,
3680 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003681 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003682 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 builder,
3684 &match_pos)) break;
3685 }
3686 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003687 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3688 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689 if (SearchStringMultiple(isolate,
3690 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003691 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003692 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003693 builder,
3694 &match_pos)) break;
3695 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 if (SearchStringMultiple(isolate,
3697 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003698 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003699 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003700 builder,
3701 &match_pos)) break;
3702 }
3703 }
3704 }
3705
3706 if (match_pos >= 0) {
3707 SetLastMatchInfoNoCaptures(subject,
3708 last_match_info,
3709 match_pos,
3710 match_pos + pattern->length());
3711 return true;
3712 }
3713 return false; // No matches at all.
3714}
3715
3716
3717static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 Handle<String> subject,
3720 Handle<JSRegExp> regexp,
3721 Handle<JSArray> last_match_array,
3722 FixedArrayBuilder* builder) {
3723 ASSERT(subject->IsFlat());
3724 int match_start = -1;
3725 int match_end = 0;
3726 int pos = 0;
3727 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3728 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3729
3730 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003731 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003732 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003733 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003734
3735 for (;;) { // Break on failure, return on exception.
3736 RegExpImpl::IrregexpResult result =
3737 RegExpImpl::IrregexpExecOnce(regexp,
3738 subject,
3739 pos,
3740 register_vector);
3741 if (result == RegExpImpl::RE_SUCCESS) {
3742 match_start = register_vector[0];
3743 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3744 if (match_end < match_start) {
3745 ReplacementStringBuilder::AddSubjectSlice(builder,
3746 match_end,
3747 match_start);
3748 }
3749 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003750 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003751 if (!first) {
3752 builder->Add(*isolate->factory()->NewProperSubString(subject,
3753 match_start,
3754 match_end));
3755 } else {
3756 builder->Add(*isolate->factory()->NewSubString(subject,
3757 match_start,
3758 match_end));
3759 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003760 if (match_start != match_end) {
3761 pos = match_end;
3762 } else {
3763 pos = match_end + 1;
3764 if (pos > subject_length) break;
3765 }
3766 } else if (result == RegExpImpl::RE_FAILURE) {
3767 break;
3768 } else {
3769 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3770 return result;
3771 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003772 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003773 }
3774
3775 if (match_start >= 0) {
3776 if (match_end < subject_length) {
3777 ReplacementStringBuilder::AddSubjectSlice(builder,
3778 match_end,
3779 subject_length);
3780 }
3781 SetLastMatchInfoNoCaptures(subject,
3782 last_match_array,
3783 match_start,
3784 match_end);
3785 return RegExpImpl::RE_SUCCESS;
3786 } else {
3787 return RegExpImpl::RE_FAILURE; // No matches at all.
3788 }
3789}
3790
3791
3792static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003794 Handle<String> subject,
3795 Handle<JSRegExp> regexp,
3796 Handle<JSArray> last_match_array,
3797 FixedArrayBuilder* builder) {
3798
3799 ASSERT(subject->IsFlat());
3800 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3801 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3802
3803 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003804 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003805
3806 RegExpImpl::IrregexpResult result =
3807 RegExpImpl::IrregexpExecOnce(regexp,
3808 subject,
3809 0,
3810 register_vector);
3811
3812 int capture_count = regexp->CaptureCount();
3813 int subject_length = subject->length();
3814
3815 // Position to search from.
3816 int pos = 0;
3817 // End of previous match. Differs from pos if match was empty.
3818 int match_end = 0;
3819 if (result == RegExpImpl::RE_SUCCESS) {
3820 // Need to keep a copy of the previous match for creating last_match_info
3821 // at the end, so we have two vectors that we swap between.
3822 OffsetsVector registers2(required_registers);
3823 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003824 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003825 do {
3826 int match_start = register_vector[0];
3827 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3828 if (match_end < match_start) {
3829 ReplacementStringBuilder::AddSubjectSlice(builder,
3830 match_end,
3831 match_start);
3832 }
3833 match_end = register_vector[1];
3834
3835 {
3836 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 // Arguments array to replace function is match, captures, index and
3839 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003840 Handle<FixedArray> elements =
3841 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003842 Handle<String> match;
3843 if (!first) {
3844 match = isolate->factory()->NewProperSubString(subject,
3845 match_start,
3846 match_end);
3847 } else {
3848 match = isolate->factory()->NewSubString(subject,
3849 match_start,
3850 match_end);
3851 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003852 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003853 for (int i = 1; i <= capture_count; i++) {
3854 int start = register_vector[i * 2];
3855 if (start >= 0) {
3856 int end = register_vector[i * 2 + 1];
3857 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003858 Handle<String> substring;
3859 if (!first) {
3860 substring = isolate->factory()->NewProperSubString(subject,
3861 start,
3862 end);
3863 } else {
3864 substring = isolate->factory()->NewSubString(subject, start, end);
3865 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003866 elements->set(i, *substring);
3867 } else {
3868 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003869 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003870 }
3871 }
3872 elements->set(capture_count + 1, Smi::FromInt(match_start));
3873 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003875 }
3876 // Swap register vectors, so the last successful match is in
3877 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003878 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003879 prev_register_vector = register_vector;
3880 register_vector = tmp;
3881
3882 if (match_end > match_start) {
3883 pos = match_end;
3884 } else {
3885 pos = match_end + 1;
3886 if (pos > subject_length) {
3887 break;
3888 }
3889 }
3890
3891 result = RegExpImpl::IrregexpExecOnce(regexp,
3892 subject,
3893 pos,
3894 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003896 } while (result == RegExpImpl::RE_SUCCESS);
3897
3898 if (result != RegExpImpl::RE_EXCEPTION) {
3899 // Finished matching, with at least one match.
3900 if (match_end < subject_length) {
3901 ReplacementStringBuilder::AddSubjectSlice(builder,
3902 match_end,
3903 subject_length);
3904 }
3905
3906 int last_match_capture_count = (capture_count + 1) * 2;
3907 int last_match_array_size =
3908 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3909 last_match_array->EnsureSize(last_match_array_size);
3910 AssertNoAllocation no_gc;
3911 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3912 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3913 RegExpImpl::SetLastSubject(elements, *subject);
3914 RegExpImpl::SetLastInput(elements, *subject);
3915 for (int i = 0; i < last_match_capture_count; i++) {
3916 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3917 }
3918 return RegExpImpl::RE_SUCCESS;
3919 }
3920 }
3921 // No matches at all, return failure or exception result directly.
3922 return result;
3923}
3924
3925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003926RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003927 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003928 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003929
3930 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003931 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3933 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3934 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3935
3936 ASSERT(last_match_info->HasFastElements());
3937 ASSERT(regexp->GetFlags().is_global());
3938 Handle<FixedArray> result_elements;
3939 if (result_array->HasFastElements()) {
3940 result_elements =
3941 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003942 }
3943 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003944 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003945 }
3946 FixedArrayBuilder builder(result_elements);
3947
3948 if (regexp->TypeTag() == JSRegExp::ATOM) {
3949 Handle<String> pattern(
3950 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003951 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003952 if (SearchStringMultiple(isolate, subject, pattern,
3953 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003954 return *builder.ToJSArray(result_array);
3955 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003956 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003957 }
3958
3959 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3960
3961 RegExpImpl::IrregexpResult result;
3962 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003963 result = SearchRegExpNoCaptureMultiple(isolate,
3964 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003965 regexp,
3966 last_match_info,
3967 &builder);
3968 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003969 result = SearchRegExpMultiple(isolate,
3970 subject,
3971 regexp,
3972 last_match_info,
3973 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003974 }
3975 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003976 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003977 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3978 return Failure::Exception();
3979}
3980
3981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003982RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 NoHandleAllocation ha;
3984 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003985 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003986 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003988 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003989 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003990 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003991 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003992 // Character array used for conversion.
3993 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003994 return isolate->heap()->
3995 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003996 }
3997 }
3998
3999 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004000 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004002 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 }
4004 if (isinf(value)) {
4005 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004006 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004007 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004008 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 MaybeObject* result =
4012 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013 DeleteArray(str);
4014 return result;
4015}
4016
4017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 NoHandleAllocation ha;
4020 ASSERT(args.length() == 2);
4021
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004022 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004024 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 }
4026 if (isinf(value)) {
4027 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004028 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004030 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004032 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 int f = FastD2I(f_number);
4034 RUNTIME_ASSERT(f >= 0);
4035 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004036 MaybeObject* res =
4037 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004039 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040}
4041
4042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004043RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004044 NoHandleAllocation ha;
4045 ASSERT(args.length() == 2);
4046
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004047 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004049 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 }
4051 if (isinf(value)) {
4052 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004053 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004057 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 int f = FastD2I(f_number);
4059 RUNTIME_ASSERT(f >= -1 && f <= 20);
4060 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004061 MaybeObject* res =
4062 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004064 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065}
4066
4067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004068RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 NoHandleAllocation ha;
4070 ASSERT(args.length() == 2);
4071
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004072 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
4076 if (isinf(value)) {
4077 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004078 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004080 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004082 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 int f = FastD2I(f_number);
4084 RUNTIME_ASSERT(f >= 1 && f <= 21);
4085 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004086 MaybeObject* res =
4087 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090}
4091
4092
4093// Returns a single character string where first character equals
4094// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004095static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004096 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004097 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004098 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004099 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004101 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102}
4103
4104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4106 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004107 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 // Handle [] indexing on Strings
4109 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004110 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4111 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 }
4113
4114 // Handle [] indexing on String objects
4115 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004116 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4117 Handle<Object> result =
4118 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4119 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 }
4121
4122 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004123 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 return prototype->GetElement(index);
4125 }
4126
4127 return object->GetElement(index);
4128}
4129
4130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004131MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4132 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004133 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004134 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 isolate->factory()->NewTypeError("non_object_property_load",
4140 HandleVector(args, 2));
4141 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 }
4143
4144 // Check if the given key is an array index.
4145 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004146 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004147 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148 }
4149
4150 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004151 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004153 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 bool has_pending_exception = false;
4156 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004157 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004159 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 }
4161
ager@chromium.org32912102009-01-16 10:38:43 +00004162 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163 // the element if so.
4164 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004165 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004167 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 }
4169}
4170
4171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004172RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 NoHandleAllocation ha;
4174 ASSERT(args.length() == 2);
4175
4176 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004177 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180}
4181
4182
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004183MaybeObject* TransitionElements(Handle<Object> object,
4184 ElementsKind to_kind,
4185 Isolate* isolate) {
4186 HandleScope scope(isolate);
4187 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4188 ElementsKind from_kind =
4189 Handle<JSObject>::cast(object)->map()->elements_kind();
4190 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4191 Handle<Object> result =
4192 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4193 if (result.is_null()) return isolate->ThrowIllegalOperation();
4194 return *result;
4195 }
4196 return isolate->ThrowIllegalOperation();
4197}
4198
4199
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004200// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004201RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004202 NoHandleAllocation ha;
4203 ASSERT(args.length() == 2);
4204
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004205 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004206 // itself.
4207 //
4208 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004209 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004210 // global proxy object never has properties. This is the case
4211 // because the global proxy object forwards everything to its hidden
4212 // prototype including local lookups.
4213 //
4214 // Additionally, we need to make sure that we do not cache results
4215 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004216 if (args[0]->IsJSObject()) {
4217 if (!args[0]->IsJSGlobalProxy() &&
4218 !args[0]->IsAccessCheckNeeded() &&
4219 args[1]->IsString()) {
4220 JSObject* receiver = JSObject::cast(args[0]);
4221 String* key = String::cast(args[1]);
4222 if (receiver->HasFastProperties()) {
4223 // Attempt to use lookup cache.
4224 Map* receiver_map = receiver->map();
4225 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4226 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4227 if (offset != -1) {
4228 Object* value = receiver->FastPropertyAt(offset);
4229 return value->IsTheHole()
4230 ? isolate->heap()->undefined_value()
4231 : value;
4232 }
4233 // Lookup cache miss. Perform lookup and update the cache if
4234 // appropriate.
4235 LookupResult result(isolate);
4236 receiver->LocalLookup(key, &result);
4237 if (result.IsProperty() && result.type() == FIELD) {
4238 int offset = result.GetFieldIndex();
4239 keyed_lookup_cache->Update(receiver_map, key, offset);
4240 return receiver->FastPropertyAt(offset);
4241 }
4242 } else {
4243 // Attempt dictionary lookup.
4244 StringDictionary* dictionary = receiver->property_dictionary();
4245 int entry = dictionary->FindEntry(key);
4246 if ((entry != StringDictionary::kNotFound) &&
4247 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4248 Object* value = dictionary->ValueAt(entry);
4249 if (!receiver->IsGlobalObject()) return value;
4250 value = JSGlobalPropertyCell::cast(value)->value();
4251 if (!value->IsTheHole()) return value;
4252 // If value is the hole do the general lookup.
4253 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004254 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004255 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4256 // JSObject without a string key. If the key is a Smi, check for a
4257 // definite out-of-bounds access to elements, which is a strong indicator
4258 // that subsequent accesses will also call the runtime. Proactively
4259 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4260 // doubles for those future calls in the case that the elements would
4261 // become FAST_DOUBLE_ELEMENTS.
4262 Handle<JSObject> js_object(args.at<JSObject>(0));
4263 ElementsKind elements_kind = js_object->GetElementsKind();
4264 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4265 elements_kind == FAST_DOUBLE_ELEMENTS) {
4266 FixedArrayBase* elements = js_object->elements();
4267 if (args.at<Smi>(1)->value() >= elements->length()) {
4268 MaybeObject* maybe_object = TransitionElements(js_object,
4269 FAST_ELEMENTS,
4270 isolate);
4271 if (maybe_object->IsFailure()) return maybe_object;
4272 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004273 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004274 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004275 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4276 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004277 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004278 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004279 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004280 if (index >= 0 && index < str->length()) {
4281 Handle<Object> result = GetCharAt(str, index);
4282 return *result;
4283 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004285
4286 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004287 return Runtime::GetObjectProperty(isolate,
4288 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004289 args.at<Object>(1));
4290}
4291
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004292// Implements part of 8.12.9 DefineOwnProperty.
4293// There are 3 cases that lead here:
4294// Step 4b - define a new accessor property.
4295// Steps 9c & 12 - replace an existing data property with an accessor property.
4296// Step 12 - update an existing accessor property with an accessor or generic
4297// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004298RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004299 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004300 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004301 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4302 CONVERT_CHECKED(String, name, args[1]);
4303 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004304 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004305 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004306 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4307 int unchecked = flag_attr->value();
4308 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4309 RUNTIME_ASSERT(!obj->IsNull());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004310 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004311 obj->LocalLookupRealNamedProperty(name, &result);
4312
4313 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4314 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4315 // delete it to avoid running into trouble in DefineAccessor, which
4316 // handles this incorrectly if the property is readonly (does nothing)
4317 if (result.IsProperty() &&
4318 (result.type() == FIELD || result.type() == NORMAL
4319 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004320 Object* ok;
4321 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004322 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004323 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4324 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 }
4326 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4327}
4328
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004329// Implements part of 8.12.9 DefineOwnProperty.
4330// There are 3 cases that lead here:
4331// Step 4a - define a new data property.
4332// Steps 9b & 12 - replace an existing accessor property with a data property.
4333// Step 12 - update an existing data property with a data or generic
4334// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004336 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004338 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4339 CONVERT_ARG_CHECKED(String, name, 1);
4340 Handle<Object> obj_value = args.at<Object>(2);
4341
4342 CONVERT_CHECKED(Smi, flag, args[3]);
4343 int unchecked = flag->value();
4344 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4345
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004346 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4347
4348 // Check if this is an element.
4349 uint32_t index;
4350 bool is_element = name->AsArrayIndex(&index);
4351
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004352 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004353 // If elements are in fast case we always implicitly assume that:
4354 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004355 if (is_element && (attr != NONE ||
4356 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004357 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004358 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004359 // We do not need to do access checks here since these has already
4360 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004361 Handle<Object> proto(js_object->GetPrototype());
4362 // If proxy is detached, ignore the assignment. Alternatively,
4363 // we could throw an exception.
4364 if (proto->IsNull()) return *obj_value;
4365 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004366 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004367
4368 // Don't allow element properties to be redefined on objects with external
4369 // array elements.
4370 if (js_object->HasExternalArrayElements()) {
4371 Handle<Object> args[2] = { js_object, name };
4372 Handle<Object> error =
4373 isolate->factory()->NewTypeError("redef_external_array_element",
4374 HandleVector(args, 2));
4375 return isolate->Throw(*error);
4376 }
4377
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004378 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004379 // Make sure that we never go back to fast case.
4380 dictionary->set_requires_slow_elements();
4381 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004382 Handle<NumberDictionary> extended_dictionary =
4383 NumberDictionarySet(dictionary, index, obj_value, details);
4384 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004385 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004386 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4387 } else {
4388 js_object->set_elements(*extended_dictionary);
4389 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004390 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004391 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004392 }
4393
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004394 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004395 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004396
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004397 // To be compatible with safari we do not change the value on API objects
4398 // in defineProperty. Firefox disagrees here, and actually changes the value.
4399 if (result.IsProperty() &&
4400 (result.type() == CALLBACKS) &&
4401 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004402 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004403 }
4404
ager@chromium.org5c838252010-02-19 08:53:10 +00004405 // Take special care when attributes are different and there is already
4406 // a property. For simplicity we normalize the property which enables us
4407 // to not worry about changing the instance_descriptor and creating a new
4408 // map. The current version of SetObjectProperty does not handle attributes
4409 // correctly in the case where a property is a field and is reset with
4410 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004411 if (result.IsProperty() &&
4412 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004413 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004414 if (js_object->IsJSGlobalProxy()) {
4415 // Since the result is a property, the prototype will exist so
4416 // we don't have to check for null.
4417 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004418 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004419 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004420 // Use IgnoreAttributes version since a readonly property may be
4421 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004422 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4423 *obj_value,
4424 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004425 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427 return Runtime::ForceSetObjectProperty(isolate,
4428 js_object,
4429 name,
4430 obj_value,
4431 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004432}
4433
4434
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004435// Special case for elements if any of the flags are true.
4436// If elements are in fast case we always implicitly assume that:
4437// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4438static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4439 Handle<JSObject> js_object,
4440 uint32_t index,
4441 Handle<Object> value,
4442 PropertyAttributes attr) {
4443 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004444 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004445 // Make sure that we never go back to fast case.
4446 dictionary->set_requires_slow_elements();
4447 PropertyDetails details = PropertyDetails(attr, NORMAL);
4448 Handle<NumberDictionary> extended_dictionary =
4449 NumberDictionarySet(dictionary, index, value, details);
4450 if (*extended_dictionary != *dictionary) {
4451 js_object->set_elements(*extended_dictionary);
4452 }
4453 return *value;
4454}
4455
4456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004457MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4458 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004459 Handle<Object> key,
4460 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004461 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004462 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004463 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 isolate->factory()->NewTypeError("non_object_property_store",
4469 HandleVector(args, 2));
4470 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 }
4472
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004473 if (object->IsJSProxy()) {
4474 bool has_pending_exception = false;
4475 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4476 if (has_pending_exception) return Failure::Exception();
4477 return JSProxy::cast(*object)->SetProperty(
4478 String::cast(*name), *value, attr, strict_mode);
4479 }
4480
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 // If the object isn't a JavaScript object, we ignore the store.
4482 if (!object->IsJSObject()) return *value;
4483
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 // Check if the given key is an array index.
4487 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004488 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4490 // of a string using [] notation. We need to support this too in
4491 // JavaScript.
4492 // In the case of a String object we just need to redirect the assignment to
4493 // the underlying string if the index is in range. Since the underlying
4494 // string does nothing with the assignment then we can ignore such
4495 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004496 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004500 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4501 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4502 }
4503
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004504 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004505 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 return *value;
4507 }
4508
4509 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004510 Handle<Object> result;
4511 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004512 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4513 return NormalizeObjectSetElement(isolate,
4514 js_object,
4515 index,
4516 value,
4517 attr);
4518 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004519 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004520 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004521 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004522 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004523 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004525 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004526 return *value;
4527 }
4528
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530 bool has_pending_exception = false;
4531 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4532 if (has_pending_exception) return Failure::Exception();
4533 Handle<String> name = Handle<String>::cast(converted);
4534
4535 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004536 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004538 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539 }
4540}
4541
4542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004543MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4544 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004545 Handle<Object> key,
4546 Handle<Object> value,
4547 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004548 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004549
4550 // Check if the given key is an array index.
4551 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004552 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004553 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4554 // of a string using [] notation. We need to support this too in
4555 // JavaScript.
4556 // In the case of a String object we just need to redirect the assignment to
4557 // the underlying string if the index is in range. Since the underlying
4558 // string does nothing with the assignment then we can ignore such
4559 // assignments.
4560 if (js_object->IsStringObjectWithCharacterAt(index)) {
4561 return *value;
4562 }
4563
whesse@chromium.org7b260152011-06-20 15:33:18 +00004564 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004565 }
4566
4567 if (key->IsString()) {
4568 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004569 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004570 } else {
4571 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004572 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004573 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4574 *value,
4575 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004576 }
4577 }
4578
4579 // Call-back into JavaScript to convert the key to a string.
4580 bool has_pending_exception = false;
4581 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4582 if (has_pending_exception) return Failure::Exception();
4583 Handle<String> name = Handle<String>::cast(converted);
4584
4585 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004586 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004587 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004588 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004589 }
4590}
4591
4592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004593MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004594 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004595 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004596 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004597
4598 // Check if the given key is an array index.
4599 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004600 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004601 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4602 // characters of a string using [] notation. In the case of a
4603 // String object we just need to redirect the deletion to the
4604 // underlying string if the index is in range. Since the
4605 // underlying string does nothing with the deletion, we can ignore
4606 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004607 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004608 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004609 }
4610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004611 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004612 }
4613
4614 Handle<String> key_string;
4615 if (key->IsString()) {
4616 key_string = Handle<String>::cast(key);
4617 } else {
4618 // Call-back into JavaScript to convert the key to a string.
4619 bool has_pending_exception = false;
4620 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4621 if (has_pending_exception) return Failure::Exception();
4622 key_string = Handle<String>::cast(converted);
4623 }
4624
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004625 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004626 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004627}
4628
4629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004630RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004631 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004632 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633
4634 Handle<Object> object = args.at<Object>(0);
4635 Handle<Object> key = args.at<Object>(1);
4636 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004637 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004638 RUNTIME_ASSERT(
4639 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004640 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004641 PropertyAttributes attributes =
4642 static_cast<PropertyAttributes>(unchecked_attributes);
4643
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004644 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004645 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004646 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4647 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 return Runtime::SetObjectProperty(isolate,
4651 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004652 key,
4653 value,
4654 attributes,
4655 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004656}
4657
4658
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004659RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4660 NoHandleAllocation ha;
4661 RUNTIME_ASSERT(args.length() == 1);
4662 Handle<Object> object = args.at<Object>(0);
4663 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4664}
4665
4666
4667RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4668 NoHandleAllocation ha;
4669 RUNTIME_ASSERT(args.length() == 1);
4670 Handle<Object> object = args.at<Object>(0);
4671 return TransitionElements(object, FAST_ELEMENTS, isolate);
4672}
4673
4674
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004675// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004676// This is used to decide if we should transform null and undefined
4677// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004678RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004679 NoHandleAllocation ha;
4680 RUNTIME_ASSERT(args.length() == 1);
4681
4682 Handle<Object> object = args.at<Object>(0);
4683
4684 if (object->IsJSFunction()) {
4685 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004686 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004687 }
4688 return isolate->heap()->undefined_value();
4689}
4690
4691
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4693 RUNTIME_ASSERT(args.length() == 5);
4694 CONVERT_ARG_CHECKED(JSObject, object, 0);
4695 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4696 Handle<Object> value = args.at<Object>(2);
4697 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4698 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4699 HandleScope scope;
4700
4701 Object* raw_boilerplate_object = literals->get(literal_index);
4702 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4703#if DEBUG
4704 ElementsKind elements_kind = object->GetElementsKind();
4705#endif
4706 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4707 // Smis should never trigger transitions.
4708 ASSERT(!value->IsSmi());
4709
4710 if (value->IsNumber()) {
4711 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4712 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4713 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4714 FixedDoubleArray* double_array =
4715 FixedDoubleArray::cast(object->elements());
4716 HeapNumber* number = HeapNumber::cast(*value);
4717 double_array->set(store_index, number->Number());
4718 } else {
4719 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4720 elements_kind == FAST_DOUBLE_ELEMENTS);
4721 TransitionElementsKind(object, FAST_ELEMENTS);
4722 FixedArray* object_array =
4723 FixedArray::cast(object->elements());
4724 object_array->set(store_index, *value);
4725 }
4726 return *object;
4727}
4728
4729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730// Set a local property, even if it is READ_ONLY. If the property does not
4731// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004733 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004734 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735 CONVERT_CHECKED(JSObject, object, args[0]);
4736 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004737 // Compute attributes.
4738 PropertyAttributes attributes = NONE;
4739 if (args.length() == 4) {
4740 CONVERT_CHECKED(Smi, value_obj, args[3]);
4741 int unchecked_value = value_obj->value();
4742 // Only attribute bits should be set.
4743 RUNTIME_ASSERT(
4744 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4745 attributes = static_cast<PropertyAttributes>(unchecked_value);
4746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004748 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004749 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750}
4751
4752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004753RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004755 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004757 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004759 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004760 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004761 ? JSReceiver::STRICT_DELETION
4762 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763}
4764
4765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004766static Object* HasLocalPropertyImplementation(Isolate* isolate,
4767 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004768 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004770 // Handle hidden prototypes. If there's a hidden prototype above this thing
4771 // then we have to check it for properties, because they are supposed to
4772 // look like they are on this object.
4773 Handle<Object> proto(object->GetPrototype());
4774 if (proto->IsJSObject() &&
4775 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004776 return HasLocalPropertyImplementation(isolate,
4777 Handle<JSObject>::cast(proto),
4778 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004779 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004780 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004781}
4782
4783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004784RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 NoHandleAllocation ha;
4786 ASSERT(args.length() == 2);
4787 CONVERT_CHECKED(String, key, args[1]);
4788
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004789 uint32_t index;
4790 const bool key_is_array_index = key->AsArrayIndex(&index);
4791
ager@chromium.org9085a012009-05-11 19:22:57 +00004792 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004794 if (obj->IsJSObject()) {
4795 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004796 // Fast case: either the key is a real named property or it is not
4797 // an array index and there are no interceptors or hidden
4798 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004799 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004800 Map* map = object->map();
4801 if (!key_is_array_index &&
4802 !map->has_named_interceptor() &&
4803 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4804 return isolate->heap()->false_value();
4805 }
4806 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004807 HandleScope scope(isolate);
4808 return HasLocalPropertyImplementation(isolate,
4809 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004810 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004811 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004813 String* string = String::cast(obj);
4814 if (index < static_cast<uint32_t>(string->length())) {
4815 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 }
4817 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004818 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819}
4820
4821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004822RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 NoHandleAllocation na;
4824 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004825 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4826 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004828 bool result = receiver->HasProperty(key);
4829 if (isolate->has_pending_exception()) return Failure::Exception();
4830 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831}
4832
4833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004834RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835 NoHandleAllocation na;
4836 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004837 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4838 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004840 bool result = receiver->HasElement(index->value());
4841 if (isolate->has_pending_exception()) return Failure::Exception();
4842 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843}
4844
4845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004846RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847 NoHandleAllocation ha;
4848 ASSERT(args.length() == 2);
4849
4850 CONVERT_CHECKED(JSObject, object, args[0]);
4851 CONVERT_CHECKED(String, key, args[1]);
4852
4853 uint32_t index;
4854 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004855 JSObject::LocalElementType type = object->HasLocalElement(index);
4856 switch (type) {
4857 case JSObject::UNDEFINED_ELEMENT:
4858 case JSObject::STRING_CHARACTER_ELEMENT:
4859 return isolate->heap()->false_value();
4860 case JSObject::INTERCEPTED_ELEMENT:
4861 case JSObject::FAST_ELEMENT:
4862 return isolate->heap()->true_value();
4863 case JSObject::DICTIONARY_ELEMENT: {
4864 if (object->IsJSGlobalProxy()) {
4865 Object* proto = object->GetPrototype();
4866 if (proto->IsNull()) {
4867 return isolate->heap()->false_value();
4868 }
4869 ASSERT(proto->IsJSGlobalObject());
4870 object = JSObject::cast(proto);
4871 }
4872 FixedArray* elements = FixedArray::cast(object->elements());
4873 NumberDictionary* dictionary = NULL;
4874 if (elements->map() ==
4875 isolate->heap()->non_strict_arguments_elements_map()) {
4876 dictionary = NumberDictionary::cast(elements->get(1));
4877 } else {
4878 dictionary = NumberDictionary::cast(elements);
4879 }
4880 int entry = dictionary->FindEntry(index);
4881 ASSERT(entry != NumberDictionary::kNotFound);
4882 PropertyDetails details = dictionary->DetailsAt(entry);
4883 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4884 }
4885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 }
4887
ager@chromium.org870a0b62008-11-04 11:43:05 +00004888 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890}
4891
4892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004893RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004895 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004896 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4897 bool threw = false;
4898 Handle<JSArray> result = GetKeysFor(object, &threw);
4899 if (threw) return Failure::Exception();
4900 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901}
4902
4903
4904// Returns either a FixedArray as Runtime_GetPropertyNames,
4905// or, if the given object has an enum cache that contains
4906// all enumerable properties of the object and its prototypes
4907// have none, the map of the object. This is used to speed up
4908// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004909RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004910 ASSERT(args.length() == 1);
4911
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004912 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004913
4914 if (raw_object->IsSimpleEnum()) return raw_object->map();
4915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004917 Handle<JSReceiver> object(raw_object);
4918 bool threw = false;
4919 Handle<FixedArray> content =
4920 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4921 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922
4923 // Test again, since cache may have been built by preceding call.
4924 if (object->IsSimpleEnum()) return object->map();
4925
4926 return *content;
4927}
4928
4929
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004930// Find the length of the prototype chain that is to to handled as one. If a
4931// prototype object is hidden it is to be viewed as part of the the object it
4932// is prototype for.
4933static int LocalPrototypeChainLength(JSObject* obj) {
4934 int count = 1;
4935 Object* proto = obj->GetPrototype();
4936 while (proto->IsJSObject() &&
4937 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4938 count++;
4939 proto = JSObject::cast(proto)->GetPrototype();
4940 }
4941 return count;
4942}
4943
4944
4945// Return the names of the local named properties.
4946// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004947RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 ASSERT(args.length() == 1);
4950 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004951 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004952 }
4953 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4954
4955 // Skip the global proxy as it has no properties and always delegates to the
4956 // real global object.
4957 if (obj->IsJSGlobalProxy()) {
4958 // Only collect names if access is permitted.
4959 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004960 !isolate->MayNamedAccess(*obj,
4961 isolate->heap()->undefined_value(),
4962 v8::ACCESS_KEYS)) {
4963 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4964 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004965 }
4966 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4967 }
4968
4969 // Find the number of objects making up this.
4970 int length = LocalPrototypeChainLength(*obj);
4971
4972 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004973 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004974 int total_property_count = 0;
4975 Handle<JSObject> jsproto = obj;
4976 for (int i = 0; i < length; i++) {
4977 // Only collect names if access is permitted.
4978 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 !isolate->MayNamedAccess(*jsproto,
4980 isolate->heap()->undefined_value(),
4981 v8::ACCESS_KEYS)) {
4982 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4983 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984 }
4985 int n;
4986 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4987 local_property_count[i] = n;
4988 total_property_count += n;
4989 if (i < length - 1) {
4990 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4991 }
4992 }
4993
4994 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 Handle<FixedArray> names =
4996 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004997
4998 // Get the property names.
4999 jsproto = obj;
5000 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005001 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005002 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005003 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5004 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005005 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005006 proto_with_hidden_properties++;
5007 }
5008 if (i < length - 1) {
5009 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5010 }
5011 }
5012
5013 // Filter out name of hidden propeties object.
5014 if (proto_with_hidden_properties > 0) {
5015 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017 names->length() - proto_with_hidden_properties);
5018 int dest_pos = 0;
5019 for (int i = 0; i < total_property_count; i++) {
5020 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005022 continue;
5023 }
5024 names->set(dest_pos++, name);
5025 }
5026 }
5027
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005028 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005029}
5030
5031
5032// Return the names of the local indexed properties.
5033// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005034RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005035 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005036 ASSERT(args.length() == 1);
5037 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005039 }
5040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5041
5042 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005043 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005044 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046}
5047
5048
5049// Return information on whether an object has a named or indexed interceptor.
5050// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005051RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005053 ASSERT(args.length() == 1);
5054 if (!args[0]->IsJSObject()) {
5055 return Smi::FromInt(0);
5056 }
5057 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5058
5059 int result = 0;
5060 if (obj->HasNamedInterceptor()) result |= 2;
5061 if (obj->HasIndexedInterceptor()) result |= 1;
5062
5063 return Smi::FromInt(result);
5064}
5065
5066
5067// Return property names from named interceptor.
5068// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005069RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005071 ASSERT(args.length() == 1);
5072 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5073
5074 if (obj->HasNamedInterceptor()) {
5075 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5076 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005079}
5080
5081
5082// Return element names from indexed interceptor.
5083// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005084RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005086 ASSERT(args.length() == 1);
5087 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5088
5089 if (obj->HasIndexedInterceptor()) {
5090 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5091 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5092 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005094}
5095
5096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005097RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005098 ASSERT_EQ(args.length(), 1);
5099 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005100 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005101 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005102
5103 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005104 // Do access checks before going to the global object.
5105 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005107 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5109 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005110 }
5111
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005112 Handle<Object> proto(object->GetPrototype());
5113 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005115 object = Handle<JSObject>::cast(proto);
5116 }
5117
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005118 bool threw = false;
5119 Handle<FixedArray> contents =
5120 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5121 if (threw) return Failure::Exception();
5122
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005123 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5124 // property array and since the result is mutable we have to create
5125 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005126 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005127 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005128 for (int i = 0; i < length; i++) {
5129 Object* entry = contents->get(i);
5130 if (entry->IsString()) {
5131 copy->set(i, entry);
5132 } else {
5133 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005134 HandleScope scope(isolate);
5135 Handle<Object> entry_handle(entry, isolate);
5136 Handle<Object> entry_str =
5137 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005138 copy->set(i, *entry_str);
5139 }
5140 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005142}
5143
5144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005145RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005146 NoHandleAllocation ha;
5147 ASSERT(args.length() == 1);
5148
5149 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005150 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005151 it.AdvanceToArgumentsFrame();
5152 JavaScriptFrame* frame = it.frame();
5153
5154 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005155 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156
5157 // Try to convert the key to an index. If successful and within
5158 // index return the the argument from the frame.
5159 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005160 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005161 return frame->GetParameter(index);
5162 }
5163
5164 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005166 bool exception = false;
5167 Handle<Object> converted =
5168 Execution::ToString(args.at<Object>(0), &exception);
5169 if (exception) return Failure::Exception();
5170 Handle<String> key = Handle<String>::cast(converted);
5171
5172 // Try to convert the string key into an array index.
5173 if (key->AsArrayIndex(&index)) {
5174 if (index < n) {
5175 return frame->GetParameter(index);
5176 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178 }
5179 }
5180
5181 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5183 if (key->Equals(isolate->heap()->callee_symbol())) {
5184 Object* function = frame->function();
5185 if (function->IsJSFunction() &&
5186 JSFunction::cast(function)->shared()->strict_mode()) {
5187 return isolate->Throw(*isolate->factory()->NewTypeError(
5188 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5189 }
5190 return function;
5191 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192
5193 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195}
5196
5197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005198RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005200
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005201 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005202 Handle<Object> object = args.at<Object>(0);
5203 if (object->IsJSObject()) {
5204 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005205 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005206 MaybeObject* ok = js_object->TransformToFastProperties(0);
5207 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005208 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005209 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005210 return *object;
5211}
5212
5213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005214RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005216
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005217 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005218 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005219 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005220 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005222 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005223 return *object;
5224}
5225
5226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005227RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 NoHandleAllocation ha;
5229 ASSERT(args.length() == 1);
5230
5231 return args[0]->ToBoolean();
5232}
5233
5234
5235// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5236// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005237RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238 NoHandleAllocation ha;
5239
5240 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005241 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 HeapObject* heap_obj = HeapObject::cast(obj);
5243
5244 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005245 if (heap_obj->map()->is_undetectable()) {
5246 return isolate->heap()->undefined_symbol();
5247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248
5249 InstanceType instance_type = heap_obj->map()->instance_type();
5250 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005251 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 }
5253
5254 switch (instance_type) {
5255 case ODDBALL_TYPE:
5256 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005258 }
5259 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005260 return FLAG_harmony_typeof
5261 ? isolate->heap()->null_symbol()
5262 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263 }
5264 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005266 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005267 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005268 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 default:
5270 // For any kind of object not handled above, the spec rule for
5271 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273 }
5274}
5275
5276
lrn@chromium.org25156de2010-04-06 13:10:27 +00005277static bool AreDigits(const char*s, int from, int to) {
5278 for (int i = from; i < to; i++) {
5279 if (s[i] < '0' || s[i] > '9') return false;
5280 }
5281
5282 return true;
5283}
5284
5285
5286static int ParseDecimalInteger(const char*s, int from, int to) {
5287 ASSERT(to - from < 10); // Overflow is not possible.
5288 ASSERT(from < to);
5289 int d = s[from] - '0';
5290
5291 for (int i = from + 1; i < to; i++) {
5292 d = 10 * d + (s[i] - '0');
5293 }
5294
5295 return d;
5296}
5297
5298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005299RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005300 NoHandleAllocation ha;
5301 ASSERT(args.length() == 1);
5302 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005303 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005304
5305 // Fast case: short integer or some sorts of junk values.
5306 int len = subject->length();
5307 if (subject->IsSeqAsciiString()) {
5308 if (len == 0) return Smi::FromInt(0);
5309
5310 char const* data = SeqAsciiString::cast(subject)->GetChars();
5311 bool minus = (data[0] == '-');
5312 int start_pos = (minus ? 1 : 0);
5313
5314 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005316 } else if (data[start_pos] > '9') {
5317 // Fast check for a junk value. A valid string may start from a
5318 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5319 // the 'I' character ('Infinity'). All of that have codes not greater than
5320 // '9' except 'I'.
5321 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005322 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005323 }
5324 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5325 // The maximal/minimal smi has 10 digits. If the string has less digits we
5326 // know it will fit into the smi-data type.
5327 int d = ParseDecimalInteger(data, start_pos, len);
5328 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005329 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005330 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005331 } else if (!subject->HasHashCode() &&
5332 len <= String::kMaxArrayIndexSize &&
5333 (len == 1 || data[0] != '0')) {
5334 // String hash is not calculated yet but all the data are present.
5335 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005336 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005337#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005338 subject->Hash(); // Force hash calculation.
5339 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5340 static_cast<int>(hash));
5341#endif
5342 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005343 }
5344 return Smi::FromInt(d);
5345 }
5346 }
5347
5348 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005349 return isolate->heap()->NumberFromDouble(
5350 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351}
5352
5353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005354RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 1);
5357
5358 CONVERT_CHECKED(JSArray, codes, args[0]);
5359 int length = Smi::cast(codes->length())->value();
5360
5361 // Check if the string can be ASCII.
5362 int i;
5363 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005364 Object* element;
5365 { MaybeObject* maybe_element = codes->GetElement(i);
5366 // We probably can't get an exception here, but just in order to enforce
5367 // the checking of inputs in the runtime calls we check here.
5368 if (!maybe_element->ToObject(&element)) return maybe_element;
5369 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5371 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5372 break;
5373 }
5374
lrn@chromium.org303ada72010-10-27 09:33:13 +00005375 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005377 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005379 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380 }
5381
lrn@chromium.org303ada72010-10-27 09:33:13 +00005382 Object* object = NULL;
5383 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 String* result = String::cast(object);
5385 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005386 Object* element;
5387 { MaybeObject* maybe_element = codes->GetElement(i);
5388 if (!maybe_element->ToObject(&element)) return maybe_element;
5389 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005391 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 }
5393 return result;
5394}
5395
5396
5397// kNotEscaped is generated by the following:
5398//
5399// #!/bin/perl
5400// for (my $i = 0; $i < 256; $i++) {
5401// print "\n" if $i % 16 == 0;
5402// my $c = chr($i);
5403// my $escaped = 1;
5404// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5405// print $escaped ? "0, " : "1, ";
5406// }
5407
5408
5409static bool IsNotEscaped(uint16_t character) {
5410 // Only for 8 bit characters, the rest are always escaped (in a different way)
5411 ASSERT(character < 256);
5412 static const char kNotEscaped[256] = {
5413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5419 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5426 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5427 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5429 };
5430 return kNotEscaped[character] != 0;
5431}
5432
5433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005434RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 const char hex_chars[] = "0123456789ABCDEF";
5436 NoHandleAllocation ha;
5437 ASSERT(args.length() == 1);
5438 CONVERT_CHECKED(String, source, args[0]);
5439
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005440 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441
5442 int escaped_length = 0;
5443 int length = source->length();
5444 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 Access<StringInputBuffer> buffer(
5446 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 buffer->Reset(source);
5448 while (buffer->has_more()) {
5449 uint16_t character = buffer->GetNext();
5450 if (character >= 256) {
5451 escaped_length += 6;
5452 } else if (IsNotEscaped(character)) {
5453 escaped_length++;
5454 } else {
5455 escaped_length += 3;
5456 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005457 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005458 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005459 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005460 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 return Failure::OutOfMemoryException();
5462 }
5463 }
5464 }
5465 // No length change implies no change. Return original string if no change.
5466 if (escaped_length == length) {
5467 return source;
5468 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005469 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005470 { MaybeObject* maybe_o =
5471 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005472 if (!maybe_o->ToObject(&o)) return maybe_o;
5473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 String* destination = String::cast(o);
5475 int dest_position = 0;
5476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005477 Access<StringInputBuffer> buffer(
5478 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 buffer->Rewind();
5480 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005481 uint16_t chr = buffer->GetNext();
5482 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005483 destination->Set(dest_position, '%');
5484 destination->Set(dest_position+1, 'u');
5485 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5486 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5487 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5488 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005490 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005491 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 dest_position++;
5493 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005494 destination->Set(dest_position, '%');
5495 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5496 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 dest_position += 3;
5498 }
5499 }
5500 return destination;
5501}
5502
5503
5504static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5505 static const signed char kHexValue['g'] = {
5506 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5507 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5508 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5509 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5510 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5511 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5512 -1, 10, 11, 12, 13, 14, 15 };
5513
5514 if (character1 > 'f') return -1;
5515 int hi = kHexValue[character1];
5516 if (hi == -1) return -1;
5517 if (character2 > 'f') return -1;
5518 int lo = kHexValue[character2];
5519 if (lo == -1) return -1;
5520 return (hi << 4) + lo;
5521}
5522
5523
ager@chromium.org870a0b62008-11-04 11:43:05 +00005524static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005525 int i,
5526 int length,
5527 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005529 int32_t hi = 0;
5530 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 if (character == '%' &&
5532 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005533 source->Get(i + 1) == 'u' &&
5534 (hi = TwoDigitHex(source->Get(i + 2),
5535 source->Get(i + 3))) != -1 &&
5536 (lo = TwoDigitHex(source->Get(i + 4),
5537 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005538 *step = 6;
5539 return (hi << 8) + lo;
5540 } else if (character == '%' &&
5541 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005542 (lo = TwoDigitHex(source->Get(i + 1),
5543 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 *step = 3;
5545 return lo;
5546 } else {
5547 *step = 1;
5548 return character;
5549 }
5550}
5551
5552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005553RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554 NoHandleAllocation ha;
5555 ASSERT(args.length() == 1);
5556 CONVERT_CHECKED(String, source, args[0]);
5557
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005558 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559
5560 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005561 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562
5563 int unescaped_length = 0;
5564 for (int i = 0; i < length; unescaped_length++) {
5565 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005566 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005567 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005568 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569 i += step;
5570 }
5571
5572 // No length change implies no change. Return original string if no change.
5573 if (unescaped_length == length)
5574 return source;
5575
lrn@chromium.org303ada72010-10-27 09:33:13 +00005576 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005577 { MaybeObject* maybe_o =
5578 ascii ?
5579 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5580 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005581 if (!maybe_o->ToObject(&o)) return maybe_o;
5582 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583 String* destination = String::cast(o);
5584
5585 int dest_position = 0;
5586 for (int i = 0; i < length; dest_position++) {
5587 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005588 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589 i += step;
5590 }
5591 return destination;
5592}
5593
5594
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005595static const unsigned int kQuoteTableLength = 128u;
5596
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005597static const int kJsonQuotesCharactersPerEntry = 8;
5598static const char* const JsonQuotes =
5599 "\\u0000 \\u0001 \\u0002 \\u0003 "
5600 "\\u0004 \\u0005 \\u0006 \\u0007 "
5601 "\\b \\t \\n \\u000b "
5602 "\\f \\r \\u000e \\u000f "
5603 "\\u0010 \\u0011 \\u0012 \\u0013 "
5604 "\\u0014 \\u0015 \\u0016 \\u0017 "
5605 "\\u0018 \\u0019 \\u001a \\u001b "
5606 "\\u001c \\u001d \\u001e \\u001f "
5607 " ! \\\" # "
5608 "$ % & ' "
5609 "( ) * + "
5610 ", - . / "
5611 "0 1 2 3 "
5612 "4 5 6 7 "
5613 "8 9 : ; "
5614 "< = > ? "
5615 "@ A B C "
5616 "D E F G "
5617 "H I J K "
5618 "L M N O "
5619 "P Q R S "
5620 "T U V W "
5621 "X Y Z [ "
5622 "\\\\ ] ^ _ "
5623 "` a b c "
5624 "d e f g "
5625 "h i j k "
5626 "l m n o "
5627 "p q r s "
5628 "t u v w "
5629 "x y z { "
5630 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005631
5632
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005633// For a string that is less than 32k characters it should always be
5634// possible to allocate it in new space.
5635static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5636
5637
5638// Doing JSON quoting cannot make the string more than this many times larger.
5639static const int kJsonQuoteWorstCaseBlowup = 6;
5640
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005641static const int kSpaceForQuotesAndComma = 3;
5642static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643
5644// Covers the entire ASCII range (all other characters are unchanged by JSON
5645// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005646static const byte JsonQuoteLengths[kQuoteTableLength] = {
5647 6, 6, 6, 6, 6, 6, 6, 6,
5648 2, 2, 2, 6, 2, 2, 6, 6,
5649 6, 6, 6, 6, 6, 6, 6, 6,
5650 6, 6, 6, 6, 6, 6, 6, 6,
5651 1, 1, 2, 1, 1, 1, 1, 1,
5652 1, 1, 1, 1, 1, 1, 1, 1,
5653 1, 1, 1, 1, 1, 1, 1, 1,
5654 1, 1, 1, 1, 1, 1, 1, 1,
5655 1, 1, 1, 1, 1, 1, 1, 1,
5656 1, 1, 1, 1, 1, 1, 1, 1,
5657 1, 1, 1, 1, 1, 1, 1, 1,
5658 1, 1, 1, 1, 2, 1, 1, 1,
5659 1, 1, 1, 1, 1, 1, 1, 1,
5660 1, 1, 1, 1, 1, 1, 1, 1,
5661 1, 1, 1, 1, 1, 1, 1, 1,
5662 1, 1, 1, 1, 1, 1, 1, 1,
5663};
5664
5665
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005666template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005667MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005668
5669
5670template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5672 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005673}
5674
5675
5676template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005677MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5678 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005679}
5680
5681
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005682template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005683static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5684 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005685 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005686 const Char* read_cursor = characters.start();
5687 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005688 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005689 int quoted_length = kSpaceForQuotes;
5690 while (read_cursor < end) {
5691 Char c = *(read_cursor++);
5692 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5693 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005694 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005695 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005696 }
5697 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005698 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5699 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005700 Object* new_object;
5701 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005702 return new_alloc;
5703 }
5704 StringType* new_string = StringType::cast(new_object);
5705
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005706 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005707 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005708 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005709 *(write_cursor++) = '"';
5710
5711 read_cursor = characters.start();
5712 while (read_cursor < end) {
5713 Char c = *(read_cursor++);
5714 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5715 *(write_cursor++) = c;
5716 } else {
5717 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5718 const char* replacement = JsonQuotes +
5719 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5720 for (int i = 0; i < len; i++) {
5721 *write_cursor++ = *replacement++;
5722 }
5723 }
5724 }
5725 *(write_cursor++) = '"';
5726 return new_string;
5727}
5728
5729
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005730template <typename SinkChar, typename SourceChar>
5731static inline SinkChar* WriteQuoteJsonString(
5732 Isolate* isolate,
5733 SinkChar* write_cursor,
5734 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005735 // SinkChar is only char if SourceChar is guaranteed to be char.
5736 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005737 const SourceChar* read_cursor = characters.start();
5738 const SourceChar* end = read_cursor + characters.length();
5739 *(write_cursor++) = '"';
5740 while (read_cursor < end) {
5741 SourceChar c = *(read_cursor++);
5742 if (sizeof(SourceChar) > 1u &&
5743 static_cast<unsigned>(c) >= kQuoteTableLength) {
5744 *(write_cursor++) = static_cast<SinkChar>(c);
5745 } else {
5746 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5747 const char* replacement = JsonQuotes +
5748 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5749 write_cursor[0] = replacement[0];
5750 if (len > 1) {
5751 write_cursor[1] = replacement[1];
5752 if (len > 2) {
5753 ASSERT(len == 6);
5754 write_cursor[2] = replacement[2];
5755 write_cursor[3] = replacement[3];
5756 write_cursor[4] = replacement[4];
5757 write_cursor[5] = replacement[5];
5758 }
5759 }
5760 write_cursor += len;
5761 }
5762 }
5763 *(write_cursor++) = '"';
5764 return write_cursor;
5765}
5766
5767
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005768template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769static MaybeObject* QuoteJsonString(Isolate* isolate,
5770 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005771 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005772 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005773 int worst_case_length =
5774 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005775 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005776 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005777 }
5778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005779 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5780 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005781 Object* new_object;
5782 if (!new_alloc->ToObject(&new_object)) {
5783 return new_alloc;
5784 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005785 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005786 // Even if our string is small enough to fit in new space we still have to
5787 // handle it being allocated in old space as may happen in the third
5788 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5789 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005791 }
5792 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005794
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005795 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005796 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005797 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005798 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5799 write_cursor,
5800 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005801 int final_length = static_cast<int>(
5802 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005803 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005804 isolate->heap()->new_space()->
5805 template ShrinkStringAtAllocationBoundary<StringType>(
5806 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005807 return new_string;
5808}
5809
5810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005811RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005812 NoHandleAllocation ha;
5813 CONVERT_CHECKED(String, str, args[0]);
5814 if (!str->IsFlat()) {
5815 MaybeObject* try_flatten = str->TryFlatten();
5816 Object* flat;
5817 if (!try_flatten->ToObject(&flat)) {
5818 return try_flatten;
5819 }
5820 str = String::cast(flat);
5821 ASSERT(str->IsFlat());
5822 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005823 String::FlatContent flat = str->GetFlatContent();
5824 ASSERT(flat.IsFlat());
5825 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005827 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005828 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005830 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005831 }
5832}
5833
5834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005835RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005836 NoHandleAllocation ha;
5837 CONVERT_CHECKED(String, str, args[0]);
5838 if (!str->IsFlat()) {
5839 MaybeObject* try_flatten = str->TryFlatten();
5840 Object* flat;
5841 if (!try_flatten->ToObject(&flat)) {
5842 return try_flatten;
5843 }
5844 str = String::cast(flat);
5845 ASSERT(str->IsFlat());
5846 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005847 String::FlatContent flat = str->GetFlatContent();
5848 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005849 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005850 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005851 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005853 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005854 }
5855}
5856
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857
5858template <typename Char, typename StringType>
5859static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5860 FixedArray* array,
5861 int worst_case_length) {
5862 int length = array->length();
5863
5864 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5865 worst_case_length);
5866 Object* new_object;
5867 if (!new_alloc->ToObject(&new_object)) {
5868 return new_alloc;
5869 }
5870 if (!isolate->heap()->new_space()->Contains(new_object)) {
5871 // Even if our string is small enough to fit in new space we still have to
5872 // handle it being allocated in old space as may happen in the third
5873 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5874 // CEntryStub::GenerateCore.
5875 return isolate->heap()->undefined_value();
5876 }
5877 AssertNoAllocation no_gc;
5878 StringType* new_string = StringType::cast(new_object);
5879 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5880
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005881 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005882 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005883 *(write_cursor++) = '[';
5884 for (int i = 0; i < length; i++) {
5885 if (i != 0) *(write_cursor++) = ',';
5886 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005887 String::FlatContent content = str->GetFlatContent();
5888 ASSERT(content.IsFlat());
5889 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005890 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5891 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005892 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005893 } else {
5894 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5895 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005896 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005897 }
5898 }
5899 *(write_cursor++) = ']';
5900
5901 int final_length = static_cast<int>(
5902 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005903 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005904 isolate->heap()->new_space()->
5905 template ShrinkStringAtAllocationBoundary<StringType>(
5906 new_string, final_length);
5907 return new_string;
5908}
5909
5910
5911RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5912 NoHandleAllocation ha;
5913 ASSERT(args.length() == 1);
5914 CONVERT_CHECKED(JSArray, array, args[0]);
5915
5916 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5917 FixedArray* elements = FixedArray::cast(array->elements());
5918 int n = elements->length();
5919 bool ascii = true;
5920 int total_length = 0;
5921
5922 for (int i = 0; i < n; i++) {
5923 Object* elt = elements->get(i);
5924 if (!elt->IsString()) return isolate->heap()->undefined_value();
5925 String* element = String::cast(elt);
5926 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5927 total_length += element->length();
5928 if (ascii && element->IsTwoByteRepresentation()) {
5929 ascii = false;
5930 }
5931 }
5932
5933 int worst_case_length =
5934 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5935 + total_length * kJsonQuoteWorstCaseBlowup;
5936
5937 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5938 return isolate->heap()->undefined_value();
5939 }
5940
5941 if (ascii) {
5942 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5943 elements,
5944 worst_case_length);
5945 } else {
5946 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5947 elements,
5948 worst_case_length);
5949 }
5950}
5951
5952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005953RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 NoHandleAllocation ha;
5955
5956 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005957 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005959 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960
lrn@chromium.org25156de2010-04-06 13:10:27 +00005961 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005962 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005963 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964}
5965
5966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 NoHandleAllocation ha;
5969 CONVERT_CHECKED(String, str, args[0]);
5970
5971 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005972 double value = StringToDouble(isolate->unicode_cache(),
5973 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
5975 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977}
5978
5979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005980template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005981MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005983 String* s,
5984 int length,
5985 int input_string_length,
5986 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005987 // We try this twice, once with the assumption that the result is no longer
5988 // than the input and, if that assumption breaks, again with the exact
5989 // length. This may not be pretty, but it is nicer than what was here before
5990 // and I hereby claim my vaffel-is.
5991 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 // Allocate the resulting string.
5993 //
5994 // NOTE: This assumes that the upper/lower case of an ascii
5995 // character is also ascii. This is currently the case, but it
5996 // might break in the future if we implement more context and locale
5997 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005998 Object* o;
5999 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 ? isolate->heap()->AllocateRawAsciiString(length)
6001 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006002 if (!maybe_o->ToObject(&o)) return maybe_o;
6003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 String* result = String::cast(o);
6005 bool has_changed_character = false;
6006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 // Convert all characters to upper case, assuming that they will fit
6008 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006009 Access<StringInputBuffer> buffer(
6010 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006012 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 // We can assume that the string is not empty
6014 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006015 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006016 bool has_next = buffer->has_more();
6017 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 int char_length = mapping->get(current, next, chars);
6019 if (char_length == 0) {
6020 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006021 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 i++;
6023 } else if (char_length == 1) {
6024 // Common case: converting the letter resulted in one character.
6025 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006026 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 has_changed_character = true;
6028 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 // We've assumed that the result would be as long as the
6031 // input but here is a character that converts to several
6032 // characters. No matter, we calculate the exact length
6033 // of the result and try the whole thing again.
6034 //
6035 // Note that this leaves room for optimization. We could just
6036 // memcpy what we already have to the result string. Also,
6037 // the result string is the last object allocated we could
6038 // "realloc" it and probably, in the vast majority of cases,
6039 // extend the existing string to be able to hold the full
6040 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006041 int next_length = 0;
6042 if (has_next) {
6043 next_length = mapping->get(next, 0, chars);
6044 if (next_length == 0) next_length = 1;
6045 }
6046 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006047 while (buffer->has_more()) {
6048 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006049 // NOTE: we use 0 as the next character here because, while
6050 // the next character may affect what a character converts to,
6051 // it does not in any case affect the length of what it convert
6052 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 int char_length = mapping->get(current, 0, chars);
6054 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006055 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006056 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006058 return Failure::OutOfMemoryException();
6059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006061 // Try again with the real length.
6062 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 } else {
6064 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006065 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066 i++;
6067 }
6068 has_changed_character = true;
6069 }
6070 current = next;
6071 }
6072 if (has_changed_character) {
6073 return result;
6074 } else {
6075 // If we didn't actually change anything in doing the conversion
6076 // we simple return the result and let the converted string
6077 // become garbage; there is no reason to keep two identical strings
6078 // alive.
6079 return s;
6080 }
6081}
6082
6083
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084namespace {
6085
lrn@chromium.org303ada72010-10-27 09:33:13 +00006086static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6087
6088
6089// Given a word and two range boundaries returns a word with high bit
6090// set in every byte iff the corresponding input byte was strictly in
6091// the range (m, n). All the other bits in the result are cleared.
6092// This function is only useful when it can be inlined and the
6093// boundaries are statically known.
6094// Requires: all bytes in the input word and the boundaries must be
6095// ascii (less than 0x7F).
6096static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6097 // Every byte in an ascii string is less than or equal to 0x7F.
6098 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6099 // Use strict inequalities since in edge cases the function could be
6100 // further simplified.
6101 ASSERT(0 < m && m < n && n < 0x7F);
6102 // Has high bit set in every w byte less than n.
6103 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6104 // Has high bit set in every w byte greater than m.
6105 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6106 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6107}
6108
6109
6110enum AsciiCaseConversion {
6111 ASCII_TO_LOWER,
6112 ASCII_TO_UPPER
6113};
6114
6115
6116template <AsciiCaseConversion dir>
6117struct FastAsciiConverter {
6118 static bool Convert(char* dst, char* src, int length) {
6119#ifdef DEBUG
6120 char* saved_dst = dst;
6121 char* saved_src = src;
6122#endif
6123 // We rely on the distance between upper and lower case letters
6124 // being a known power of 2.
6125 ASSERT('a' - 'A' == (1 << 5));
6126 // Boundaries for the range of input characters than require conversion.
6127 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6128 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6129 bool changed = false;
6130 char* const limit = src + length;
6131#ifdef V8_HOST_CAN_READ_UNALIGNED
6132 // Process the prefix of the input that requires no conversion one
6133 // (machine) word at a time.
6134 while (src <= limit - sizeof(uintptr_t)) {
6135 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6136 if (AsciiRangeMask(w, lo, hi) != 0) {
6137 changed = true;
6138 break;
6139 }
6140 *reinterpret_cast<uintptr_t*>(dst) = w;
6141 src += sizeof(uintptr_t);
6142 dst += sizeof(uintptr_t);
6143 }
6144 // Process the remainder of the input performing conversion when
6145 // required one word at a time.
6146 while (src <= limit - sizeof(uintptr_t)) {
6147 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6148 uintptr_t m = AsciiRangeMask(w, lo, hi);
6149 // The mask has high (7th) bit set in every byte that needs
6150 // conversion and we know that the distance between cases is
6151 // 1 << 5.
6152 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6153 src += sizeof(uintptr_t);
6154 dst += sizeof(uintptr_t);
6155 }
6156#endif
6157 // Process the last few bytes of the input (or the whole input if
6158 // unaligned access is not supported).
6159 while (src < limit) {
6160 char c = *src;
6161 if (lo < c && c < hi) {
6162 c ^= (1 << 5);
6163 changed = true;
6164 }
6165 *dst = c;
6166 ++src;
6167 ++dst;
6168 }
6169#ifdef DEBUG
6170 CheckConvert(saved_dst, saved_src, length, changed);
6171#endif
6172 return changed;
6173 }
6174
6175#ifdef DEBUG
6176 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6177 bool expected_changed = false;
6178 for (int i = 0; i < length; i++) {
6179 if (dst[i] == src[i]) continue;
6180 expected_changed = true;
6181 if (dir == ASCII_TO_LOWER) {
6182 ASSERT('A' <= src[i] && src[i] <= 'Z');
6183 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6184 } else {
6185 ASSERT(dir == ASCII_TO_UPPER);
6186 ASSERT('a' <= src[i] && src[i] <= 'z');
6187 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6188 }
6189 }
6190 ASSERT(expected_changed == changed);
6191 }
6192#endif
6193};
6194
6195
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196struct ToLowerTraits {
6197 typedef unibrow::ToLowercase UnibrowConverter;
6198
lrn@chromium.org303ada72010-10-27 09:33:13 +00006199 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006200};
6201
6202
6203struct ToUpperTraits {
6204 typedef unibrow::ToUppercase UnibrowConverter;
6205
lrn@chromium.org303ada72010-10-27 09:33:13 +00006206 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207};
6208
6209} // namespace
6210
6211
6212template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006214 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006215 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006217 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006219 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006220
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006221 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006222 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223 if (length == 0) return s;
6224
6225 // Simpler handling of ascii strings.
6226 //
6227 // NOTE: This assumes that the upper/lower case of an ascii
6228 // character is also ascii. This is currently the case, but it
6229 // might break in the future if we implement more context and locale
6230 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006231 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006232 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006234 if (!maybe_o->ToObject(&o)) return maybe_o;
6235 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006236 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006237 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006238 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239 return has_changed_character ? result : s;
6240 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006241
lrn@chromium.org303ada72010-10-27 09:33:13 +00006242 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 { MaybeObject* maybe_answer =
6244 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006245 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6246 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006247 if (answer->IsSmi()) {
6248 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006249 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 ConvertCaseHelper(isolate,
6251 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006252 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6253 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006254 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006255 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006256}
6257
6258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006259RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006260 return ConvertCase<ToLowerTraits>(
6261 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262}
6263
6264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006265RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 return ConvertCase<ToUpperTraits>(
6267 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268}
6269
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006270
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006271static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006272 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006273}
6274
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006276RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006277 NoHandleAllocation ha;
6278 ASSERT(args.length() == 3);
6279
6280 CONVERT_CHECKED(String, s, args[0]);
6281 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6282 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6283
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006284 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006285 int length = s->length();
6286
6287 int left = 0;
6288 if (trimLeft) {
6289 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6290 left++;
6291 }
6292 }
6293
6294 int right = length;
6295 if (trimRight) {
6296 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6297 right--;
6298 }
6299 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006300 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006301}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006304RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006307 CONVERT_ARG_CHECKED(String, subject, 0);
6308 CONVERT_ARG_CHECKED(String, pattern, 1);
6309 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6310
6311 int subject_length = subject->length();
6312 int pattern_length = pattern->length();
6313 RUNTIME_ASSERT(pattern_length > 0);
6314
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006315 if (limit == 0xffffffffu) {
6316 Handle<Object> cached_answer(StringSplitCache::Lookup(
6317 isolate->heap()->string_split_cache(),
6318 *subject,
6319 *pattern));
6320 if (*cached_answer != Smi::FromInt(0)) {
6321 Handle<JSArray> result =
6322 isolate->factory()->NewJSArrayWithElements(
6323 Handle<FixedArray>::cast(cached_answer));
6324 return *result;
6325 }
6326 }
6327
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006328 // The limit can be very large (0xffffffffu), but since the pattern
6329 // isn't empty, we can never create more parts than ~half the length
6330 // of the subject.
6331
6332 if (!subject->IsFlat()) FlattenString(subject);
6333
6334 static const int kMaxInitialListCapacity = 16;
6335
danno@chromium.org40cb8782011-05-25 07:58:50 +00006336 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006337
6338 // Find (up to limit) indices of separator and end-of-string in subject
6339 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6340 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006341 if (!pattern->IsFlat()) FlattenString(pattern);
6342
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006343 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006344
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006345 if (static_cast<uint32_t>(indices.length()) < limit) {
6346 indices.Add(subject_length);
6347 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006348
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006349 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006350
6351 // Create JSArray of substrings separated by separator.
6352 int part_count = indices.length();
6353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006354 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006355 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6356 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006357 result->set_length(Smi::FromInt(part_count));
6358
6359 ASSERT(result->HasFastElements());
6360
6361 if (part_count == 1 && indices.at(0) == subject_length) {
6362 FixedArray::cast(result->elements())->set(0, *subject);
6363 return *result;
6364 }
6365
6366 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6367 int part_start = 0;
6368 for (int i = 0; i < part_count; i++) {
6369 HandleScope local_loop_handle;
6370 int part_end = indices.at(i);
6371 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006372 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006373 elements->set(i, *substring);
6374 part_start = part_end + pattern_length;
6375 }
6376
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006377 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006378 if (result->HasFastElements()) {
6379 StringSplitCache::Enter(isolate->heap(),
6380 isolate->heap()->string_split_cache(),
6381 *subject,
6382 *pattern,
6383 *elements);
6384 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006385 }
6386
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006387 return *result;
6388}
6389
6390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391// Copies ascii characters to the given fixed array looking up
6392// one-char strings in the cache. Gives up on the first char that is
6393// not in the cache and fills the remainder with smi zeros. Returns
6394// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395static int CopyCachedAsciiCharsToArray(Heap* heap,
6396 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 FixedArray* elements,
6398 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006399 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006400 FixedArray* ascii_cache = heap->single_character_string_cache();
6401 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006402 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006403 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006404 for (i = 0; i < length; ++i) {
6405 Object* value = ascii_cache->get(chars[i]);
6406 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006407 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408 }
6409 if (i < length) {
6410 ASSERT(Smi::FromInt(0) == 0);
6411 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6412 }
6413#ifdef DEBUG
6414 for (int j = 0; j < length; ++j) {
6415 Object* element = elements->get(j);
6416 ASSERT(element == Smi::FromInt(0) ||
6417 (element->IsString() && String::cast(element)->LooksValid()));
6418 }
6419#endif
6420 return i;
6421}
6422
6423
6424// Converts a String to JSArray.
6425// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006426RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006427 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006428 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006429 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006430 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006431
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006432 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006433 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006434
6435 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006436 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006438 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006439 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 { MaybeObject* maybe_obj =
6441 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006442 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6443 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006445 String::FlatContent content = s->GetFlatContent();
6446 if (content.IsAscii()) {
6447 Vector<const char> chars = content.ToAsciiVector();
6448 // Note, this will initialize all elements (not only the prefix)
6449 // to prevent GC from seeing partially initialized array.
6450 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6451 chars.start(),
6452 *elements,
6453 length);
6454 } else {
6455 MemsetPointer(elements->data_start(),
6456 isolate->heap()->undefined_value(),
6457 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006458 }
6459 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006461 }
6462 for (int i = position; i < length; ++i) {
6463 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6464 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006465 }
6466
6467#ifdef DEBUG
6468 for (int i = 0; i < length; ++i) {
6469 ASSERT(String::cast(elements->get(i))->length() == 1);
6470 }
6471#endif
6472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006473 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006474}
6475
6476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006477RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006478 NoHandleAllocation ha;
6479 ASSERT(args.length() == 1);
6480 CONVERT_CHECKED(String, value, args[0]);
6481 return value->ToObject();
6482}
6483
6484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006486 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006487 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006488 return char_length == 0;
6489}
6490
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 1);
6495
6496 Object* number = args[0];
6497 RUNTIME_ASSERT(number->IsNumber());
6498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500}
6501
6502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006503RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006504 NoHandleAllocation ha;
6505 ASSERT(args.length() == 1);
6506
6507 Object* number = args[0];
6508 RUNTIME_ASSERT(number->IsNumber());
6509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006510 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006511}
6512
6513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006514RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515 NoHandleAllocation ha;
6516 ASSERT(args.length() == 1);
6517
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006518 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006519
6520 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6521 if (number > 0 && number <= Smi::kMaxValue) {
6522 return Smi::FromInt(static_cast<int>(number));
6523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006528RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006529 NoHandleAllocation ha;
6530 ASSERT(args.length() == 1);
6531
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006532 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006533
6534 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6535 if (number > 0 && number <= Smi::kMaxValue) {
6536 return Smi::FromInt(static_cast<int>(number));
6537 }
6538
6539 double double_value = DoubleToInteger(number);
6540 // Map both -0 and +0 to +0.
6541 if (double_value == 0) double_value = 0;
6542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006544}
6545
6546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006547RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006548 NoHandleAllocation ha;
6549 ASSERT(args.length() == 1);
6550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006551 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006552 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553}
6554
6555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006556RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557 NoHandleAllocation ha;
6558 ASSERT(args.length() == 1);
6559
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006560 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006561
6562 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6563 if (number > 0 && number <= Smi::kMaxValue) {
6564 return Smi::FromInt(static_cast<int>(number));
6565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006566 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567}
6568
6569
ager@chromium.org870a0b62008-11-04 11:43:05 +00006570// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6571// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 1);
6575
6576 Object* obj = args[0];
6577 if (obj->IsSmi()) {
6578 return obj;
6579 }
6580 if (obj->IsHeapNumber()) {
6581 double value = HeapNumber::cast(obj)->value();
6582 int int_value = FastD2I(value);
6583 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6584 return Smi::FromInt(int_value);
6585 }
6586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006588}
6589
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006591RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006592 NoHandleAllocation ha;
6593 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006595}
6596
6597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006598RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599 NoHandleAllocation ha;
6600 ASSERT(args.length() == 2);
6601
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006602 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6603 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006604 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605}
6606
6607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006608RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609 NoHandleAllocation ha;
6610 ASSERT(args.length() == 2);
6611
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006612 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6613 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006614 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615}
6616
6617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006618RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 NoHandleAllocation ha;
6620 ASSERT(args.length() == 2);
6621
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006622 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6623 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 1);
6631
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006632 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006637RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 0);
6640
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006642}
6643
6644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006645RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 NoHandleAllocation ha;
6647 ASSERT(args.length() == 2);
6648
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006649 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6650 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652}
6653
6654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006655RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 NoHandleAllocation ha;
6657 ASSERT(args.length() == 2);
6658
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006659 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6660 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661
ager@chromium.org3811b432009-10-28 14:53:37 +00006662 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006663 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665}
6666
6667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006668RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 NoHandleAllocation ha;
6670 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 CONVERT_CHECKED(String, str1, args[0]);
6672 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006673 isolate->counters()->string_add_runtime()->Increment();
6674 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675}
6676
6677
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006678template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006679static inline void StringBuilderConcatHelper(String* special,
6680 sinkchar* sink,
6681 FixedArray* fixed_array,
6682 int array_length) {
6683 int position = 0;
6684 for (int i = 0; i < array_length; i++) {
6685 Object* element = fixed_array->get(i);
6686 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006687 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006688 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006689 int pos;
6690 int len;
6691 if (encoded_slice > 0) {
6692 // Position and length encoded in one smi.
6693 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6694 len = StringBuilderSubstringLength::decode(encoded_slice);
6695 } else {
6696 // Position and length encoded in two smis.
6697 Object* obj = fixed_array->get(++i);
6698 ASSERT(obj->IsSmi());
6699 pos = Smi::cast(obj)->value();
6700 len = -encoded_slice;
6701 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006702 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006703 sink + position,
6704 pos,
6705 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006706 position += len;
6707 } else {
6708 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006709 int element_length = string->length();
6710 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006711 position += element_length;
6712 }
6713 }
6714}
6715
6716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006717RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006719 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006721 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006722 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006723 return Failure::OutOfMemoryException();
6724 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006725 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006726 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006727
6728 // This assumption is used by the slice encoding in one or two smis.
6729 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6730
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006731 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6732 if (maybe_result->IsFailure()) return maybe_result;
6733
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006734 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006736 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 }
6738 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006739 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742
6743 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745 } else if (array_length == 1) {
6746 Object* first = fixed_array->get(0);
6747 if (first->IsString()) return first;
6748 }
6749
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006750 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 int position = 0;
6752 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006753 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 Object* elt = fixed_array->get(i);
6755 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006756 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006757 int smi_value = Smi::cast(elt)->value();
6758 int pos;
6759 int len;
6760 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006761 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006762 pos = StringBuilderSubstringPosition::decode(smi_value);
6763 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006764 } else {
6765 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006766 len = -smi_value;
6767 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006768 i++;
6769 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006770 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006771 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006772 Object* next_smi = fixed_array->get(i);
6773 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006775 }
6776 pos = Smi::cast(next_smi)->value();
6777 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006779 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006781 ASSERT(pos >= 0);
6782 ASSERT(len >= 0);
6783 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006785 }
6786 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787 } else if (elt->IsString()) {
6788 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006789 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006790 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006791 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006793 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006797 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006799 return Failure::OutOfMemoryException();
6800 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006801 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 }
6803
6804 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 { MaybeObject* maybe_object =
6809 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006810 if (!maybe_object->ToObject(&object)) return maybe_object;
6811 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006812 SeqAsciiString* answer = SeqAsciiString::cast(object);
6813 StringBuilderConcatHelper(special,
6814 answer->GetChars(),
6815 fixed_array,
6816 array_length);
6817 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 { MaybeObject* maybe_object =
6820 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006821 if (!maybe_object->ToObject(&object)) return maybe_object;
6822 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006823 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6824 StringBuilderConcatHelper(special,
6825 answer->GetChars(),
6826 fixed_array,
6827 array_length);
6828 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830}
6831
6832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006833RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006834 NoHandleAllocation ha;
6835 ASSERT(args.length() == 3);
6836 CONVERT_CHECKED(JSArray, array, args[0]);
6837 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006839 return Failure::OutOfMemoryException();
6840 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006841 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 CONVERT_CHECKED(String, separator, args[2]);
6843
6844 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006845 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006846 }
6847 FixedArray* fixed_array = FixedArray::cast(array->elements());
6848 if (fixed_array->length() < array_length) {
6849 array_length = fixed_array->length();
6850 }
6851
6852 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006853 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006854 } else if (array_length == 1) {
6855 Object* first = fixed_array->get(0);
6856 if (first->IsString()) return first;
6857 }
6858
6859 int separator_length = separator->length();
6860 int max_nof_separators =
6861 (String::kMaxLength + separator_length - 1) / separator_length;
6862 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006863 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006864 return Failure::OutOfMemoryException();
6865 }
6866 int length = (array_length - 1) * separator_length;
6867 for (int i = 0; i < array_length; i++) {
6868 Object* element_obj = fixed_array->get(i);
6869 if (!element_obj->IsString()) {
6870 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006871 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006872 }
6873 String* element = String::cast(element_obj);
6874 int increment = element->length();
6875 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006876 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006877 return Failure::OutOfMemoryException();
6878 }
6879 length += increment;
6880 }
6881
6882 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006883 { MaybeObject* maybe_object =
6884 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006885 if (!maybe_object->ToObject(&object)) return maybe_object;
6886 }
6887 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6888
6889 uc16* sink = answer->GetChars();
6890#ifdef DEBUG
6891 uc16* end = sink + length;
6892#endif
6893
6894 String* first = String::cast(fixed_array->get(0));
6895 int first_length = first->length();
6896 String::WriteToFlat(first, sink, 0, first_length);
6897 sink += first_length;
6898
6899 for (int i = 1; i < array_length; i++) {
6900 ASSERT(sink + separator_length <= end);
6901 String::WriteToFlat(separator, sink, 0, separator_length);
6902 sink += separator_length;
6903
6904 String* element = String::cast(fixed_array->get(i));
6905 int element_length = element->length();
6906 ASSERT(sink + element_length <= end);
6907 String::WriteToFlat(element, sink, 0, element_length);
6908 sink += element_length;
6909 }
6910 ASSERT(sink == end);
6911
6912 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6913 return answer;
6914}
6915
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006916template <typename Char>
6917static void JoinSparseArrayWithSeparator(FixedArray* elements,
6918 int elements_length,
6919 uint32_t array_length,
6920 String* separator,
6921 Vector<Char> buffer) {
6922 int previous_separator_position = 0;
6923 int separator_length = separator->length();
6924 int cursor = 0;
6925 for (int i = 0; i < elements_length; i += 2) {
6926 int position = NumberToInt32(elements->get(i));
6927 String* string = String::cast(elements->get(i + 1));
6928 int string_length = string->length();
6929 if (string->length() > 0) {
6930 while (previous_separator_position < position) {
6931 String::WriteToFlat<Char>(separator, &buffer[cursor],
6932 0, separator_length);
6933 cursor += separator_length;
6934 previous_separator_position++;
6935 }
6936 String::WriteToFlat<Char>(string, &buffer[cursor],
6937 0, string_length);
6938 cursor += string->length();
6939 }
6940 }
6941 if (separator_length > 0) {
6942 // Array length must be representable as a signed 32-bit number,
6943 // otherwise the total string length would have been too large.
6944 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6945 int last_array_index = static_cast<int>(array_length - 1);
6946 while (previous_separator_position < last_array_index) {
6947 String::WriteToFlat<Char>(separator, &buffer[cursor],
6948 0, separator_length);
6949 cursor += separator_length;
6950 previous_separator_position++;
6951 }
6952 }
6953 ASSERT(cursor <= buffer.length());
6954}
6955
6956
6957RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6958 NoHandleAllocation ha;
6959 ASSERT(args.length() == 3);
6960 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006961 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6962 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006963 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6964 CONVERT_CHECKED(String, separator, args[2]);
6965 // elements_array is fast-mode JSarray of alternating positions
6966 // (increasing order) and strings.
6967 // array_length is length of original array (used to add separators);
6968 // separator is string to put between elements. Assumed to be non-empty.
6969
6970 // Find total length of join result.
6971 int string_length = 0;
6972 bool is_ascii = true;
6973 int max_string_length = SeqAsciiString::kMaxLength;
6974 bool overflow = false;
6975 CONVERT_NUMBER_CHECKED(int, elements_length,
6976 Int32, elements_array->length());
6977 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6978 FixedArray* elements = FixedArray::cast(elements_array->elements());
6979 for (int i = 0; i < elements_length; i += 2) {
6980 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6981 CONVERT_CHECKED(String, string, elements->get(i + 1));
6982 int length = string->length();
6983 if (is_ascii && !string->IsAsciiRepresentation()) {
6984 is_ascii = false;
6985 max_string_length = SeqTwoByteString::kMaxLength;
6986 }
6987 if (length > max_string_length ||
6988 max_string_length - length < string_length) {
6989 overflow = true;
6990 break;
6991 }
6992 string_length += length;
6993 }
6994 int separator_length = separator->length();
6995 if (!overflow && separator_length > 0) {
6996 if (array_length <= 0x7fffffffu) {
6997 int separator_count = static_cast<int>(array_length) - 1;
6998 int remaining_length = max_string_length - string_length;
6999 if ((remaining_length / separator_length) >= separator_count) {
7000 string_length += separator_length * (array_length - 1);
7001 } else {
7002 // Not room for the separators within the maximal string length.
7003 overflow = true;
7004 }
7005 } else {
7006 // Nonempty separator and at least 2^31-1 separators necessary
7007 // means that the string is too large to create.
7008 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7009 overflow = true;
7010 }
7011 }
7012 if (overflow) {
7013 // Throw OutOfMemory exception for creating too large a string.
7014 V8::FatalProcessOutOfMemory("Array join result too large.");
7015 }
7016
7017 if (is_ascii) {
7018 MaybeObject* result_allocation =
7019 isolate->heap()->AllocateRawAsciiString(string_length);
7020 if (result_allocation->IsFailure()) return result_allocation;
7021 SeqAsciiString* result_string =
7022 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7023 JoinSparseArrayWithSeparator<char>(elements,
7024 elements_length,
7025 array_length,
7026 separator,
7027 Vector<char>(result_string->GetChars(),
7028 string_length));
7029 return result_string;
7030 } else {
7031 MaybeObject* result_allocation =
7032 isolate->heap()->AllocateRawTwoByteString(string_length);
7033 if (result_allocation->IsFailure()) return result_allocation;
7034 SeqTwoByteString* result_string =
7035 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7036 JoinSparseArrayWithSeparator<uc16>(elements,
7037 elements_length,
7038 array_length,
7039 separator,
7040 Vector<uc16>(result_string->GetChars(),
7041 string_length));
7042 return result_string;
7043 }
7044}
7045
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007047RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048 NoHandleAllocation ha;
7049 ASSERT(args.length() == 2);
7050
7051 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7052 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054}
7055
7056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007057RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 NoHandleAllocation ha;
7059 ASSERT(args.length() == 2);
7060
7061 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7062 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064}
7065
7066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 NoHandleAllocation ha;
7069 ASSERT(args.length() == 2);
7070
7071 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7072 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074}
7075
7076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007077RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078 NoHandleAllocation ha;
7079 ASSERT(args.length() == 1);
7080
7081 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007082 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007083}
7084
7085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007086RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087 NoHandleAllocation ha;
7088 ASSERT(args.length() == 2);
7089
7090 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7091 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007092 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093}
7094
7095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007096RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097 NoHandleAllocation ha;
7098 ASSERT(args.length() == 2);
7099
7100 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7101 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007102 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103}
7104
7105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 NoHandleAllocation ha;
7108 ASSERT(args.length() == 2);
7109
7110 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7111 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007112 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007113}
7114
7115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007116RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117 NoHandleAllocation ha;
7118 ASSERT(args.length() == 2);
7119
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007120 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7121 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007122 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7123 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7124 if (x == y) return Smi::FromInt(EQUAL);
7125 Object* result;
7126 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7127 result = Smi::FromInt(EQUAL);
7128 } else {
7129 result = Smi::FromInt(NOT_EQUAL);
7130 }
7131 return result;
7132}
7133
7134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007135RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007136 NoHandleAllocation ha;
7137 ASSERT(args.length() == 2);
7138
7139 CONVERT_CHECKED(String, x, args[0]);
7140 CONVERT_CHECKED(String, y, args[1]);
7141
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007142 bool not_equal = !x->Equals(y);
7143 // This is slightly convoluted because the value that signifies
7144 // equality is 0 and inequality is 1 so we have to negate the result
7145 // from String::Equals.
7146 ASSERT(not_equal == 0 || not_equal == 1);
7147 STATIC_CHECK(EQUAL == 0);
7148 STATIC_CHECK(NOT_EQUAL == 1);
7149 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007150}
7151
7152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007153RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007154 NoHandleAllocation ha;
7155 ASSERT(args.length() == 3);
7156
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007157 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7158 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007159 if (isnan(x) || isnan(y)) return args[2];
7160 if (x == y) return Smi::FromInt(EQUAL);
7161 if (isless(x, y)) return Smi::FromInt(LESS);
7162 return Smi::FromInt(GREATER);
7163}
7164
7165
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007166// Compare two Smis as if they were converted to strings and then
7167// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007168RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007169 NoHandleAllocation ha;
7170 ASSERT(args.length() == 2);
7171
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007172 // Extract the integer values from the Smis.
7173 CONVERT_CHECKED(Smi, x, args[0]);
7174 CONVERT_CHECKED(Smi, y, args[1]);
7175 int x_value = x->value();
7176 int y_value = y->value();
7177
7178 // If the integers are equal so are the string representations.
7179 if (x_value == y_value) return Smi::FromInt(EQUAL);
7180
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007181 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007182 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007183 if (x_value == 0 || y_value == 0)
7184 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007185
ager@chromium.org32912102009-01-16 10:38:43 +00007186 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007187 // smallest because the char code of '-' is less than the char code
7188 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007189
7190 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7191 // architectures using 32-bit Smis.
7192 uint32_t x_scaled = x_value;
7193 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007194 if (x_value < 0 || y_value < 0) {
7195 if (y_value >= 0) return Smi::FromInt(LESS);
7196 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007197 x_scaled = -x_value;
7198 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007199 }
7200
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007201 static const uint32_t kPowersOf10[] = {
7202 1, 10, 100, 1000, 10*1000, 100*1000,
7203 1000*1000, 10*1000*1000, 100*1000*1000,
7204 1000*1000*1000
7205 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007206
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007207 // If the integers have the same number of decimal digits they can be
7208 // compared directly as the numeric order is the same as the
7209 // lexicographic order. If one integer has fewer digits, it is scaled
7210 // by some power of 10 to have the same number of digits as the longer
7211 // integer. If the scaled integers are equal it means the shorter
7212 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007214 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7215 int x_log2 = IntegerLog2(x_scaled);
7216 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7217 x_log10 -= x_scaled < kPowersOf10[x_log10];
7218
7219 int y_log2 = IntegerLog2(y_scaled);
7220 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7221 y_log10 -= y_scaled < kPowersOf10[y_log10];
7222
7223 int tie = EQUAL;
7224
7225 if (x_log10 < y_log10) {
7226 // X has fewer digits. We would like to simply scale up X but that
7227 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7228 // be scaled up to 9_000_000_000. So we scale up by the next
7229 // smallest power and scale down Y to drop one digit. It is OK to
7230 // drop one digit from the longer integer since the final digit is
7231 // past the length of the shorter integer.
7232 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7233 y_scaled /= 10;
7234 tie = LESS;
7235 } else if (y_log10 < x_log10) {
7236 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7237 x_scaled /= 10;
7238 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007239 }
7240
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007241 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7242 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7243 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007244}
7245
7246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007247static Object* StringInputBufferCompare(RuntimeState* state,
7248 String* x,
7249 String* y) {
7250 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7251 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007252 bufx.Reset(x);
7253 bufy.Reset(y);
7254 while (bufx.has_more() && bufy.has_more()) {
7255 int d = bufx.GetNext() - bufy.GetNext();
7256 if (d < 0) return Smi::FromInt(LESS);
7257 else if (d > 0) return Smi::FromInt(GREATER);
7258 }
7259
7260 // x is (non-trivial) prefix of y:
7261 if (bufy.has_more()) return Smi::FromInt(LESS);
7262 // y is prefix of x:
7263 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7264}
7265
7266
7267static Object* FlatStringCompare(String* x, String* y) {
7268 ASSERT(x->IsFlat());
7269 ASSERT(y->IsFlat());
7270 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7271 int prefix_length = x->length();
7272 if (y->length() < prefix_length) {
7273 prefix_length = y->length();
7274 equal_prefix_result = Smi::FromInt(GREATER);
7275 } else if (y->length() > prefix_length) {
7276 equal_prefix_result = Smi::FromInt(LESS);
7277 }
7278 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007279 String::FlatContent x_content = x->GetFlatContent();
7280 String::FlatContent y_content = y->GetFlatContent();
7281 if (x_content.IsAscii()) {
7282 Vector<const char> x_chars = x_content.ToAsciiVector();
7283 if (y_content.IsAscii()) {
7284 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007285 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007286 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007287 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007288 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7289 }
7290 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007291 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7292 if (y_content.IsAscii()) {
7293 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007294 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7295 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007296 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007297 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7298 }
7299 }
7300 Object* result;
7301 if (r == 0) {
7302 result = equal_prefix_result;
7303 } else {
7304 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7305 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 ASSERT(result ==
7307 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007308 return result;
7309}
7310
7311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313 NoHandleAllocation ha;
7314 ASSERT(args.length() == 2);
7315
7316 CONVERT_CHECKED(String, x, args[0]);
7317 CONVERT_CHECKED(String, y, args[1]);
7318
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 // A few fast case tests before we flatten.
7322 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007323 if (y->length() == 0) {
7324 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007326 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327 return Smi::FromInt(LESS);
7328 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007330 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007331 if (d < 0) return Smi::FromInt(LESS);
7332 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333
lrn@chromium.org303ada72010-10-27 09:33:13 +00007334 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007336 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7337 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007339 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7340 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007342 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344}
7345
7346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007347RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 NoHandleAllocation ha;
7349 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007350 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354}
7355
7356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007357RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007358 NoHandleAllocation ha;
7359 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007360 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007362 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364}
7365
7366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007367RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368 NoHandleAllocation ha;
7369 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007370 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007372 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374}
7375
7376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007377static const double kPiDividedBy4 = 0.78539816339744830962;
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7386 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 double result;
7388 if (isinf(x) && isinf(y)) {
7389 // Make sure that the result in case of two infinite arguments
7390 // is a multiple of Pi / 4. The sign of the result is determined
7391 // by the first argument (x) and the sign of the second argument
7392 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 int multiplier = (x < 0) ? -1 : 1;
7394 if (y < 0) multiplier *= 3;
7395 result = multiplier * kPiDividedBy4;
7396 } else {
7397 result = atan2(x, y);
7398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400}
7401
7402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410}
7411
7412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007413RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 NoHandleAllocation ha;
7415 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007416 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007418 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
7422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424 NoHandleAllocation ha;
7425 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007426 isolate->counters()->math_exp()->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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430}
7431
7432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007433RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434 NoHandleAllocation ha;
7435 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007436 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007438 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007439 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440}
7441
7442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007443RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007444 NoHandleAllocation ha;
7445 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007446 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007448 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007449 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450}
7451
7452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007453RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 NoHandleAllocation ha;
7455 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007456 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007458 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007459
7460 // If the second argument is a smi, it is much faster to call the
7461 // custom powi() function than the generic pow().
7462 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007463 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007464 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007465 }
7466
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007467 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007468 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007469}
7470
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007471// Fast version of Math.pow if we know that y is not an integer and
7472// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007473RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007474 NoHandleAllocation ha;
7475 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007476 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7477 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007478 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007479 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007480 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007481 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007482 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007483 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007484 }
7485}
7486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007488RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007489 NoHandleAllocation ha;
7490 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007491 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007493 if (!args[0]->IsHeapNumber()) {
7494 // Must be smi. Return the argument unchanged for all the other types
7495 // to make fuzz-natives test happy.
7496 return args[0];
7497 }
7498
7499 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7500
7501 double value = number->value();
7502 int exponent = number->get_exponent();
7503 int sign = number->get_sign();
7504
danno@chromium.org160a7b02011-04-18 15:51:38 +00007505 if (exponent < -1) {
7506 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7507 if (sign) return isolate->heap()->minus_zero_value();
7508 return Smi::FromInt(0);
7509 }
7510
7511 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7512 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7513 // agument holds for 32-bit smis).
7514 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007515 return Smi::FromInt(static_cast<int>(value + 0.5));
7516 }
7517
7518 // If the magnitude is big enough, there's no place for fraction part. If we
7519 // try to add 0.5 to this number, 1.0 will be added instead.
7520 if (exponent >= 52) {
7521 return number;
7522 }
7523
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007525
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007526 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007527 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007528}
7529
7530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007531RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532 NoHandleAllocation ha;
7533 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007534 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007535
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007536 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538}
7539
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542 NoHandleAllocation ha;
7543 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007544 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007546 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007547 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007548}
7549
7550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007551RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552 NoHandleAllocation ha;
7553 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007554 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007555
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007556 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007558}
7559
7560
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007561static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007562 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7563 181, 212, 243, 273, 304, 334};
7564 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7565 182, 213, 244, 274, 305, 335};
7566
7567 year += month / 12;
7568 month %= 12;
7569 if (month < 0) {
7570 year--;
7571 month += 12;
7572 }
7573
7574 ASSERT(month >= 0);
7575 ASSERT(month < 12);
7576
7577 // year_delta is an arbitrary number such that:
7578 // a) year_delta = -1 (mod 400)
7579 // b) year + year_delta > 0 for years in the range defined by
7580 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7581 // Jan 1 1970. This is required so that we don't run into integer
7582 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007583 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007584 // operations.
7585 static const int year_delta = 399999;
7586 static const int base_day = 365 * (1970 + year_delta) +
7587 (1970 + year_delta) / 4 -
7588 (1970 + year_delta) / 100 +
7589 (1970 + year_delta) / 400;
7590
7591 int year1 = year + year_delta;
7592 int day_from_year = 365 * year1 +
7593 year1 / 4 -
7594 year1 / 100 +
7595 year1 / 400 -
7596 base_day;
7597
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007598 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7599 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007600 }
7601
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007602 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007603}
7604
7605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007606RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007607 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007608 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007609
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007610 CONVERT_SMI_ARG_CHECKED(year, 0);
7611 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007612
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007613 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007614}
7615
7616
7617static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7618static const int kDaysIn4Years = 4 * 365 + 1;
7619static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7620static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7621static const int kDays1970to2000 = 30 * 365 + 7;
7622static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7623 kDays1970to2000;
7624static const int kYearsOffset = 400000;
7625
7626static const char kDayInYear[] = {
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, 31,
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,
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, 31,
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,
7635 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7636 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28, 29, 30,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29, 30,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7651
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, 31,
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,
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, 31,
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,
7660 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7661 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28, 29, 30,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7676
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, 31,
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,
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, 31,
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,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7687 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7688 22, 23, 24, 25, 26, 27, 28, 29, 30,
7689 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7690 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7691 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7692 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7693 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7694 22, 23, 24, 25, 26, 27, 28, 29, 30,
7695 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7696 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7697 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7698 22, 23, 24, 25, 26, 27, 28, 29, 30,
7699 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7700 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7701
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, 31,
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,
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, 31,
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,
7710 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7711 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7712 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7713 22, 23, 24, 25, 26, 27, 28, 29, 30,
7714 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7715 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7716 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7717 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7718 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7719 22, 23, 24, 25, 26, 27, 28, 29, 30,
7720 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7721 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7722 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7723 22, 23, 24, 25, 26, 27, 28, 29, 30,
7724 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7725 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7726
7727static const char kMonthInYear[] = {
7728 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,
7729 0, 0, 0, 0, 0, 0,
7730 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,
7731 1, 1, 1,
7732 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,
7733 2, 2, 2, 2, 2, 2,
7734 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,
7735 3, 3, 3, 3, 3,
7736 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,
7737 4, 4, 4, 4, 4, 4,
7738 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,
7739 5, 5, 5, 5, 5,
7740 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,
7741 6, 6, 6, 6, 6, 6,
7742 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,
7743 7, 7, 7, 7, 7, 7,
7744 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,
7745 8, 8, 8, 8, 8,
7746 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,
7747 9, 9, 9, 9, 9, 9,
7748 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7749 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7750 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7751 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7752
7753 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,
7754 0, 0, 0, 0, 0, 0,
7755 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,
7756 1, 1, 1,
7757 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,
7758 2, 2, 2, 2, 2, 2,
7759 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,
7760 3, 3, 3, 3, 3,
7761 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,
7762 4, 4, 4, 4, 4, 4,
7763 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,
7764 5, 5, 5, 5, 5,
7765 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,
7766 6, 6, 6, 6, 6, 6,
7767 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,
7768 7, 7, 7, 7, 7, 7,
7769 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,
7770 8, 8, 8, 8, 8,
7771 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,
7772 9, 9, 9, 9, 9, 9,
7773 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7774 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7775 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7776 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7777
7778 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,
7779 0, 0, 0, 0, 0, 0,
7780 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,
7781 1, 1, 1, 1,
7782 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,
7783 2, 2, 2, 2, 2, 2,
7784 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,
7785 3, 3, 3, 3, 3,
7786 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,
7787 4, 4, 4, 4, 4, 4,
7788 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,
7789 5, 5, 5, 5, 5,
7790 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,
7791 6, 6, 6, 6, 6, 6,
7792 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,
7793 7, 7, 7, 7, 7, 7,
7794 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,
7795 8, 8, 8, 8, 8,
7796 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,
7797 9, 9, 9, 9, 9, 9,
7798 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7799 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7800 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7801 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7802
7803 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,
7804 0, 0, 0, 0, 0, 0,
7805 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,
7806 1, 1, 1,
7807 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,
7808 2, 2, 2, 2, 2, 2,
7809 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,
7810 3, 3, 3, 3, 3,
7811 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,
7812 4, 4, 4, 4, 4, 4,
7813 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,
7814 5, 5, 5, 5, 5,
7815 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,
7816 6, 6, 6, 6, 6, 6,
7817 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,
7818 7, 7, 7, 7, 7, 7,
7819 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,
7820 8, 8, 8, 8, 8,
7821 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,
7822 9, 9, 9, 9, 9, 9,
7823 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7824 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7825 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7826 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7827
7828
7829// This function works for dates from 1970 to 2099.
7830static inline void DateYMDFromTimeAfter1970(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 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7837 date %= kDaysIn4Years;
7838
7839 month = kMonthInYear[date];
7840 day = kDayInYear[date];
7841
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007842 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007843}
7844
7845
7846static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007847 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007848#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007849 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007850#endif
7851
7852 date += kDaysOffset;
7853 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7854 date %= kDaysIn400Years;
7855
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007856 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007857
7858 date--;
7859 int yd1 = date / kDaysIn100Years;
7860 date %= kDaysIn100Years;
7861 year += 100 * yd1;
7862
7863 date++;
7864 int yd2 = date / kDaysIn4Years;
7865 date %= kDaysIn4Years;
7866 year += 4 * yd2;
7867
7868 date--;
7869 int yd3 = date / 365;
7870 date %= 365;
7871 year += yd3;
7872
7873 bool is_leap = (!yd1 || yd2) && !yd3;
7874
7875 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007876 ASSERT(is_leap || (date >= 0));
7877 ASSERT((date < 365) || (is_leap && (date < 366)));
7878 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007879 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7880 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007881
7882 if (is_leap) {
7883 day = kDayInYear[2*365 + 1 + date];
7884 month = kMonthInYear[2*365 + 1 + date];
7885 } else {
7886 day = kDayInYear[date];
7887 month = kMonthInYear[date];
7888 }
7889
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007890 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007891}
7892
7893
7894static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007895 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007896 if (date >= 0 && date < 32 * kDaysIn4Years) {
7897 DateYMDFromTimeAfter1970(date, year, month, day);
7898 } else {
7899 DateYMDFromTimeSlow(date, year, month, day);
7900 }
7901}
7902
7903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007904RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007905 NoHandleAllocation ha;
7906 ASSERT(args.length() == 2);
7907
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007908 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007909 CONVERT_CHECKED(JSArray, res_array, args[1]);
7910
7911 int year, month, day;
7912 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7913
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007914 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7915 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007916 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007917
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007918 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7919 if (maybe->IsFailure()) return maybe;
7920 FixedArray* elms = FixedArray::cast(res_array->elements());
7921 elms->set(0, Smi::FromInt(year));
7922 elms->set(1, Smi::FromInt(month));
7923 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007925 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007926}
7927
7928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007929RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007930 HandleScope scope(isolate);
7931 ASSERT(args.length() == 3);
7932
7933 Handle<JSFunction> callee = args.at<JSFunction>(0);
7934 Object** parameters = reinterpret_cast<Object**>(args[1]);
7935 const int argument_count = Smi::cast(args[2])->value();
7936
7937 Handle<JSObject> result =
7938 isolate->factory()->NewArgumentsObject(callee, argument_count);
7939 // Allocate the elements if needed.
7940 int parameter_count = callee->shared()->formal_parameter_count();
7941 if (argument_count > 0) {
7942 if (parameter_count > 0) {
7943 int mapped_count = Min(argument_count, parameter_count);
7944 Handle<FixedArray> parameter_map =
7945 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7946 parameter_map->set_map(
7947 isolate->heap()->non_strict_arguments_elements_map());
7948
7949 Handle<Map> old_map(result->map());
7950 Handle<Map> new_map =
7951 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007952 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007953
7954 result->set_map(*new_map);
7955 result->set_elements(*parameter_map);
7956
7957 // Store the context and the arguments array at the beginning of the
7958 // parameter map.
7959 Handle<Context> context(isolate->context());
7960 Handle<FixedArray> arguments =
7961 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7962 parameter_map->set(0, *context);
7963 parameter_map->set(1, *arguments);
7964
7965 // Loop over the actual parameters backwards.
7966 int index = argument_count - 1;
7967 while (index >= mapped_count) {
7968 // These go directly in the arguments array and have no
7969 // corresponding slot in the parameter map.
7970 arguments->set(index, *(parameters - index - 1));
7971 --index;
7972 }
7973
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007974 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007975 while (index >= 0) {
7976 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007977 Handle<String> name(scope_info->ParameterName(index));
7978 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007979 bool duplicate = false;
7980 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007981 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007982 duplicate = true;
7983 break;
7984 }
7985 }
7986
7987 if (duplicate) {
7988 // This goes directly in the arguments array with a hole in the
7989 // parameter map.
7990 arguments->set(index, *(parameters - index - 1));
7991 parameter_map->set_the_hole(index + 2);
7992 } else {
7993 // The context index goes in the parameter map with a hole in the
7994 // arguments array.
7995 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007996 for (int j = 0; j < context_local_count; ++j) {
7997 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007998 context_index = j;
7999 break;
8000 }
8001 }
8002 ASSERT(context_index >= 0);
8003 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008004 parameter_map->set(index + 2, Smi::FromInt(
8005 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008006 }
8007
8008 --index;
8009 }
8010 } else {
8011 // If there is no aliasing, the arguments object elements are not
8012 // special in any way.
8013 Handle<FixedArray> elements =
8014 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8015 result->set_elements(*elements);
8016 for (int i = 0; i < argument_count; ++i) {
8017 elements->set(i, *(parameters - i - 1));
8018 }
8019 }
8020 }
8021 return *result;
8022}
8023
8024
8025RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008026 NoHandleAllocation ha;
8027 ASSERT(args.length() == 3);
8028
8029 JSFunction* callee = JSFunction::cast(args[0]);
8030 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008031 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008032
lrn@chromium.org303ada72010-10-27 09:33:13 +00008033 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 { MaybeObject* maybe_result =
8035 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008036 if (!maybe_result->ToObject(&result)) return maybe_result;
8037 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008038 // Allocate the elements if needed.
8039 if (length > 0) {
8040 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008041 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008043 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8044 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008045
8046 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008047 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008048 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008049 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008050
8051 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008052 for (int i = 0; i < length; i++) {
8053 array->set(i, *--parameters, mode);
8054 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008055 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008056 }
8057 return result;
8058}
8059
8060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008061RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008062 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008063 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008064 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008065 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008066 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067
whesse@chromium.org7b260152011-06-20 15:33:18 +00008068 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008069 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008070 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008072 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8073 context,
8074 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008075 return *result;
8076}
8077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008078
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008079// Find the arguments of the JavaScript function invocation that called
8080// into C++ code. Collect these in a newly allocated array of handles (possibly
8081// prefixed by a number of empty handles).
8082static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8083 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008084 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008085 // Find frame containing arguments passed to the caller.
8086 JavaScriptFrameIterator it;
8087 JavaScriptFrame* frame = it.frame();
8088 List<JSFunction*> functions(2);
8089 frame->GetFunctions(&functions);
8090 if (functions.length() > 1) {
8091 int inlined_frame_index = functions.length() - 1;
8092 JSFunction* inlined_function = functions[inlined_frame_index];
8093 int args_count = inlined_function->shared()->formal_parameter_count();
8094 ScopedVector<SlotRef> args_slots(args_count);
8095 SlotRef::ComputeSlotMappingForArguments(frame,
8096 inlined_frame_index,
8097 &args_slots);
8098
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008099 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008100 SmartArrayPointer<Handle<Object> > param_data(
8101 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008102 for (int i = 0; i < args_count; i++) {
8103 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008104 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008105 }
8106 return param_data;
8107 } else {
8108 it.AdvanceToArgumentsFrame();
8109 frame = it.frame();
8110 int args_count = frame->ComputeParametersCount();
8111
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008112 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008113 SmartArrayPointer<Handle<Object> > param_data(
8114 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008115 for (int i = 0; i < args_count; i++) {
8116 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008117 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008118 }
8119 return param_data;
8120 }
8121}
8122
8123
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008124RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8125 HandleScope scope(isolate);
8126 ASSERT(args.length() == 4);
8127 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8128 RUNTIME_ASSERT(args[3]->IsNumber());
8129 Handle<Object> bindee = args.at<Object>(1);
8130
8131 // TODO(lrn): Create bound function in C++ code from premade shared info.
8132 bound_function->shared()->set_bound(true);
8133 // Get all arguments of calling function (Function.prototype.bind).
8134 int argc = 0;
8135 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8136 // Don't count the this-arg.
8137 if (argc > 0) {
8138 ASSERT(*arguments[0] == args[2]);
8139 argc--;
8140 } else {
8141 ASSERT(args[2]->IsUndefined());
8142 }
8143 // Initialize array of bindings (function, this, and any existing arguments
8144 // if the function was already bound).
8145 Handle<FixedArray> new_bindings;
8146 int i;
8147 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8148 Handle<FixedArray> old_bindings(
8149 JSFunction::cast(*bindee)->function_bindings());
8150 new_bindings =
8151 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8152 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8153 i = 0;
8154 for (int n = old_bindings->length(); i < n; i++) {
8155 new_bindings->set(i, old_bindings->get(i));
8156 }
8157 } else {
8158 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8159 new_bindings = isolate->factory()->NewFixedArray(array_size);
8160 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8161 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8162 i = 2;
8163 }
8164 // Copy arguments, skipping the first which is "this_arg".
8165 for (int j = 0; j < argc; j++, i++) {
8166 new_bindings->set(i, *arguments[j + 1]);
8167 }
8168 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
8169 bound_function->set_function_bindings(*new_bindings);
8170
8171 // Update length.
8172 Handle<String> length_symbol = isolate->factory()->length_symbol();
8173 Handle<Object> new_length(args.at<Object>(3));
8174 PropertyAttributes attr =
8175 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8176 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8177 return *bound_function;
8178}
8179
8180
8181RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8182 HandleScope handles(isolate);
8183 ASSERT(args.length() == 1);
8184 CONVERT_ARG_CHECKED(JSObject, callable, 0);
8185 if (callable->IsJSFunction()) {
8186 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8187 if (function->shared()->bound()) {
8188 Handle<FixedArray> bindings(function->function_bindings());
8189 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8190 return *isolate->factory()->NewJSArrayWithElements(bindings);
8191 }
8192 }
8193 return isolate->heap()->undefined_value();
8194}
8195
8196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008197RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008198 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008199 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008200 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008201 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008202 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008203
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008204 // The argument is a bound function. Extract its bound arguments
8205 // and callable.
8206 Handle<FixedArray> bound_args =
8207 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8208 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8209 Handle<Object> bound_function(
8210 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8211 ASSERT(!bound_function->IsJSFunction() ||
8212 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008214 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008215 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008216 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008217 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008218 param_data[i] = Handle<Object>(bound_args->get(
8219 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008220 }
8221
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008222 if (!bound_function->IsJSFunction()) {
8223 bool exception_thrown;
8224 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8225 &exception_thrown);
8226 if (exception_thrown) return Failure::Exception();
8227 }
8228 ASSERT(bound_function->IsJSFunction());
8229
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008230 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008231 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008232 Execution::New(Handle<JSFunction>::cast(bound_function),
8233 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008234 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008235 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008236 }
8237 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008238 return *result;
8239}
8240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242static void TrySettingInlineConstructStub(Isolate* isolate,
8243 Handle<JSFunction> function) {
8244 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008245 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008247 }
8248 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008249 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008250 Handle<Code> code = compiler.CompileConstructStub(function);
8251 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008252 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008253}
8254
8255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008256RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 ASSERT(args.length() == 1);
8259
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008260 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008262 // If the constructor isn't a proper function we throw a type error.
8263 if (!constructor->IsJSFunction()) {
8264 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8265 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008266 isolate->factory()->NewTypeError("not_constructor", arguments);
8267 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008268 }
8269
8270 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008271
8272 // If function should not have prototype, construction is not allowed. In this
8273 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008274 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008275 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8276 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 isolate->factory()->NewTypeError("not_constructor", arguments);
8278 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008279 }
8280
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008281#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008283 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 if (debug->StepInActive()) {
8285 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008286 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008287#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008289 if (function->has_initial_map()) {
8290 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008291 // The 'Function' function ignores the receiver object when
8292 // called using 'new' and creates a new JSFunction object that
8293 // is returned. The receiver object is only used for error
8294 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008296 // allocate JSFunctions since it does not properly initialize
8297 // the shared part of the function. Since the receiver is
8298 // ignored anyway, we use the global object as the receiver
8299 // instead of a new JSFunction object. This way, errors are
8300 // reported the same way whether or not 'Function' is called
8301 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304 }
8305
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008306 // The function should be compiled for the optimization hints to be
8307 // available. We cannot use EnsureCompiled because that forces a
8308 // compilation through the shared function info which makes it
8309 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008310 if (!function->is_compiled()) {
8311 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8312 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008313
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008314 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008315 if (!function->has_initial_map() &&
8316 shared->IsInobjectSlackTrackingInProgress()) {
8317 // The tracking is already in progress for another function. We can only
8318 // track one initial_map at a time, so we force the completion before the
8319 // function is called as a constructor for the first time.
8320 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008321 }
8322
8323 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8325 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008326 // Delay setting the stub if inobject slack tracking is in progress.
8327 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008328 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008329 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008331 isolate->counters()->constructed_objects()->Increment();
8332 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008333
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008334 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335}
8336
8337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008338RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008339 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008340 ASSERT(args.length() == 1);
8341
8342 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8343 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008344 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008346 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008347}
8348
8349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008350RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008351 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008352 ASSERT(args.length() == 1);
8353
8354 Handle<JSFunction> function = args.at<JSFunction>(0);
8355#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008356 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008357 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008358 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008359 PrintF("]\n");
8360 }
8361#endif
8362
lrn@chromium.org34e60782011-09-15 07:25:40 +00008363 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008364 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008365 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008366 return Failure::Exception();
8367 }
8368
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008369 // All done. Return the compiled code.
8370 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008371 return function->code();
8372}
8373
8374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008375RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008377 ASSERT(args.length() == 1);
8378 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008379
8380 // If the function is not compiled ignore the lazy
8381 // recompilation. This can happen if the debugger is activated and
8382 // the function is returned to the not compiled state.
8383 if (!function->shared()->is_compiled()) {
8384 function->ReplaceCode(function->shared()->code());
8385 return function->code();
8386 }
8387
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008388 // If the function is not optimizable or debugger is active continue using the
8389 // code from the full compiler.
8390 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008391 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008392 if (FLAG_trace_opt) {
8393 PrintF("[failed to optimize ");
8394 function->PrintName();
8395 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8396 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008397 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008398 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008399 function->ReplaceCode(function->shared()->code());
8400 return function->code();
8401 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008402 if (JSFunction::CompileOptimized(function,
8403 AstNode::kNoNumber,
8404 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405 return function->code();
8406 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008407 if (FLAG_trace_opt) {
8408 PrintF("[failed to optimize ");
8409 function->PrintName();
8410 PrintF(": optimized compilation failed]\n");
8411 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008412 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008413 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008414}
8415
8416
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008417class ActivationsFinder : public ThreadVisitor {
8418 public:
8419 explicit ActivationsFinder(JSFunction* function)
8420 : function_(function), has_activations_(false) {}
8421
8422 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8423 if (has_activations_) return;
8424
8425 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8426 JavaScriptFrame* frame = it.frame();
8427 if (frame->is_optimized() && frame->function() == function_) {
8428 has_activations_ = true;
8429 return;
8430 }
8431 }
8432 }
8433
8434 bool has_activations() { return has_activations_; }
8435
8436 private:
8437 JSFunction* function_;
8438 bool has_activations_;
8439};
8440
8441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008442RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008443 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008444 ASSERT(args.length() == 1);
8445 RUNTIME_ASSERT(args[0]->IsSmi());
8446 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008447 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008448 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8449 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008450 int frames = deoptimizer->output_count();
8451
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008452 deoptimizer->MaterializeHeapNumbers();
8453 delete deoptimizer;
8454
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008455 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008456 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008457 for (int i = 0; i < frames - 1; i++) it.Advance();
8458 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008459
8460 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008461 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008462 Handle<Object> arguments;
8463 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008465 if (arguments.is_null()) {
8466 // FunctionGetArguments can't throw an exception, so cast away the
8467 // doubt with an assert.
8468 arguments = Handle<Object>(
8469 Accessors::FunctionGetArguments(*function,
8470 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 ASSERT(*arguments != isolate->heap()->null_value());
8472 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008473 }
8474 frame->SetExpression(i, *arguments);
8475 }
8476 }
8477
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008478 if (type == Deoptimizer::EAGER) {
8479 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008480 }
8481
8482 // Avoid doing too much work when running with --always-opt and keep
8483 // the optimized code around.
8484 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008486 }
8487
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008488 // Find other optimized activations of the function.
8489 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008490 while (!it.done()) {
8491 JavaScriptFrame* frame = it.frame();
8492 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008493 has_other_activations = true;
8494 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495 }
8496 it.Advance();
8497 }
8498
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008499 if (!has_other_activations) {
8500 ActivationsFinder activations_finder(*function);
8501 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8502 has_other_activations = activations_finder.has_activations();
8503 }
8504
8505 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008506 if (FLAG_trace_deopt) {
8507 PrintF("[removing optimized code for: ");
8508 function->PrintName();
8509 PrintF("]\n");
8510 }
8511 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008512 } else {
8513 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008514 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008515 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008516}
8517
8518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008519RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008520 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008521 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008523}
8524
8525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008526RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008527 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008528 ASSERT(args.length() == 1);
8529 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008530 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008531
8532 Deoptimizer::DeoptimizeFunction(*function);
8533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008534 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008535}
8536
8537
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008538RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8539#if defined(USE_SIMULATOR)
8540 return isolate->heap()->true_value();
8541#else
8542 return isolate->heap()->false_value();
8543#endif
8544}
8545
8546
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008547RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8548 HandleScope scope(isolate);
8549 ASSERT(args.length() == 1);
8550 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8551 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8552 function->MarkForLazyRecompilation();
8553 return isolate->heap()->undefined_value();
8554}
8555
8556
lrn@chromium.org1c092762011-05-09 09:42:16 +00008557RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8558 HandleScope scope(isolate);
8559 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008560 // The least significant bit (after untagging) indicates whether the
8561 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008562 if (!V8::UseCrankshaft()) {
8563 return Smi::FromInt(4); // 4 == "never".
8564 }
8565 if (FLAG_always_opt) {
8566 return Smi::FromInt(3); // 3 == "always".
8567 }
8568 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8569 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8570 : Smi::FromInt(2); // 2 == "no".
8571}
8572
8573
8574RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8575 HandleScope scope(isolate);
8576 ASSERT(args.length() == 1);
8577 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8578 return Smi::FromInt(function->shared()->opt_count());
8579}
8580
8581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008583 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008584 ASSERT(args.length() == 1);
8585 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8586
8587 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008588 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008589
8590 // We have hit a back edge in an unoptimized frame for a function that was
8591 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008592 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008593 // Keep track of whether we've succeeded in optimizing.
8594 bool succeeded = unoptimized->optimizable();
8595 if (succeeded) {
8596 // If we are trying to do OSR when there are already optimized
8597 // activations of the function, it means (a) the function is directly or
8598 // indirectly recursive and (b) an optimized invocation has been
8599 // deoptimized so that we are currently in an unoptimized activation.
8600 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008601 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008602 while (succeeded && !it.done()) {
8603 JavaScriptFrame* frame = it.frame();
8604 succeeded = !frame->is_optimized() || frame->function() != *function;
8605 it.Advance();
8606 }
8607 }
8608
8609 int ast_id = AstNode::kNoNumber;
8610 if (succeeded) {
8611 // The top JS function is this one, the PC is somewhere in the
8612 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008613 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008614 JavaScriptFrame* frame = it.frame();
8615 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008616 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008617 ASSERT(unoptimized->contains(frame->pc()));
8618
8619 // Use linear search of the unoptimized code's stack check table to find
8620 // the AST id matching the PC.
8621 Address start = unoptimized->instruction_start();
8622 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008623 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008624 uint32_t table_length = Memory::uint32_at(table_cursor);
8625 table_cursor += kIntSize;
8626 for (unsigned i = 0; i < table_length; ++i) {
8627 // Table entries are (AST id, pc offset) pairs.
8628 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8629 if (pc_offset == target_pc_offset) {
8630 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8631 break;
8632 }
8633 table_cursor += 2 * kIntSize;
8634 }
8635 ASSERT(ast_id != AstNode::kNoNumber);
8636 if (FLAG_trace_osr) {
8637 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8638 function->PrintName();
8639 PrintF("]\n");
8640 }
8641
8642 // Try to compile the optimized code. A true return value from
8643 // CompileOptimized means that compilation succeeded, not necessarily
8644 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008645 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008646 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008647 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8648 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008649 if (data->OsrPcOffset()->value() >= 0) {
8650 if (FLAG_trace_osr) {
8651 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008652 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008653 }
8654 ASSERT(data->OsrAstId()->value() == ast_id);
8655 } else {
8656 // We may never generate the desired OSR entry if we emit an
8657 // early deoptimize.
8658 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008659 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008660 } else {
8661 succeeded = false;
8662 }
8663 }
8664
8665 // Revert to the original stack checks in the original unoptimized code.
8666 if (FLAG_trace_osr) {
8667 PrintF("[restoring original stack checks in ");
8668 function->PrintName();
8669 PrintF("]\n");
8670 }
8671 StackCheckStub check_stub;
8672 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008673 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008674 Deoptimizer::RevertStackCheckCode(*unoptimized,
8675 *check_code,
8676 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008677
8678 // Allow OSR only at nesting level zero again.
8679 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8680
8681 // If the optimization attempt succeeded, return the AST id tagged as a
8682 // smi. This tells the builtin that we need to translate the unoptimized
8683 // frame to an optimized one.
8684 if (succeeded) {
8685 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8686 return Smi::FromInt(ast_id);
8687 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008688 if (function->IsMarkedForLazyRecompilation()) {
8689 function->ReplaceCode(function->shared()->code());
8690 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008691 return Smi::FromInt(-1);
8692 }
8693}
8694
8695
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008696RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8697 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8698 return isolate->heap()->undefined_value();
8699}
8700
8701
lrn@chromium.org34e60782011-09-15 07:25:40 +00008702RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8703 HandleScope scope(isolate);
8704 ASSERT(args.length() == 5);
8705 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8706 Object* receiver = args[1];
8707 CONVERT_CHECKED(JSObject, arguments, args[2]);
8708 CONVERT_CHECKED(Smi, shift, args[3]);
8709 CONVERT_CHECKED(Smi, arity, args[4]);
8710
8711 int offset = shift->value();
8712 int argc = arity->value();
8713 ASSERT(offset >= 0);
8714 ASSERT(argc >= 0);
8715
8716 // If there are too many arguments, allocate argv via malloc.
8717 const int argv_small_size = 10;
8718 Handle<Object> argv_small_buffer[argv_small_size];
8719 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8720 Handle<Object>* argv = argv_small_buffer;
8721 if (argc > argv_small_size) {
8722 argv = new Handle<Object>[argc];
8723 if (argv == NULL) return isolate->StackOverflow();
8724 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8725 }
8726
8727 for (int i = 0; i < argc; ++i) {
8728 MaybeObject* maybe = arguments->GetElement(offset + i);
8729 Object* object;
8730 if (!maybe->To<Object>(&object)) return maybe;
8731 argv[i] = Handle<Object>(object);
8732 }
8733
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008734 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008735 Handle<JSReceiver> hfun(fun);
8736 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008737 Handle<Object> result =
8738 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008739
8740 if (threw) return Failure::Exception();
8741 return *result;
8742}
8743
8744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008745RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008746 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008747 ASSERT(args.length() == 1);
8748 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8749 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8750}
8751
8752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008753RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008754 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008755 ASSERT(args.length() == 1);
8756 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8757 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8758}
8759
8760
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008761RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008762 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008763 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764
kasper.lund7276f142008-07-30 08:49:36 +00008765 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008766 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008767 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008768 { MaybeObject* maybe_result =
8769 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008770 if (!maybe_result->ToObject(&result)) return maybe_result;
8771 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008773 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774
kasper.lund7276f142008-07-30 08:49:36 +00008775 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008776}
8777
lrn@chromium.org303ada72010-10-27 09:33:13 +00008778
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008779RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8780 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008781 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008782 JSObject* extension_object;
8783 if (args[0]->IsJSObject()) {
8784 extension_object = JSObject::cast(args[0]);
8785 } else {
8786 // Convert the object to a proper JavaScript object.
8787 MaybeObject* maybe_js_object = args[0]->ToObject();
8788 if (!maybe_js_object->To(&extension_object)) {
8789 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8790 HandleScope scope(isolate);
8791 Handle<Object> handle = args.at<Object>(0);
8792 Handle<Object> result =
8793 isolate->factory()->NewTypeError("with_expression",
8794 HandleVector(&handle, 1));
8795 return isolate->Throw(*result);
8796 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008797 return maybe_js_object;
8798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008799 }
8800 }
8801
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008802 JSFunction* function;
8803 if (args[1]->IsSmi()) {
8804 // A smi sentinel indicates a context nested inside global code rather
8805 // than some function. There is a canonical empty function that can be
8806 // gotten from the global context.
8807 function = isolate->context()->global_context()->closure();
8808 } else {
8809 function = JSFunction::cast(args[1]);
8810 }
8811
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008812 Context* context;
8813 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008814 isolate->heap()->AllocateWithContext(function,
8815 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008816 extension_object);
8817 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008818 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008819 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008820}
8821
8822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008823RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008824 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008825 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008826 String* name = String::cast(args[0]);
8827 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008828 JSFunction* function;
8829 if (args[2]->IsSmi()) {
8830 // A smi sentinel indicates a context nested inside global code rather
8831 // than some function. There is a canonical empty function that can be
8832 // gotten from the global context.
8833 function = isolate->context()->global_context()->closure();
8834 } else {
8835 function = JSFunction::cast(args[2]);
8836 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008837 Context* context;
8838 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008839 isolate->heap()->AllocateCatchContext(function,
8840 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008841 name,
8842 thrown_object);
8843 if (!maybe_context->To(&context)) return maybe_context;
8844 isolate->set_context(context);
8845 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008846}
8847
8848
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008849RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8850 NoHandleAllocation ha;
8851 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008852 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008853 JSFunction* function;
8854 if (args[1]->IsSmi()) {
8855 // A smi sentinel indicates a context nested inside global code rather
8856 // than some function. There is a canonical empty function that can be
8857 // gotten from the global context.
8858 function = isolate->context()->global_context()->closure();
8859 } else {
8860 function = JSFunction::cast(args[1]);
8861 }
8862 Context* context;
8863 MaybeObject* maybe_context =
8864 isolate->heap()->AllocateBlockContext(function,
8865 isolate->context(),
8866 scope_info);
8867 if (!maybe_context->To(&context)) return maybe_context;
8868 isolate->set_context(context);
8869 return context;
8870}
8871
8872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008873RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008875 ASSERT(args.length() == 2);
8876
8877 CONVERT_ARG_CHECKED(Context, context, 0);
8878 CONVERT_ARG_CHECKED(String, name, 1);
8879
8880 int index;
8881 PropertyAttributes attributes;
8882 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008883 BindingFlags binding_flags;
8884 Handle<Object> holder = context->Lookup(name,
8885 flags,
8886 &index,
8887 &attributes,
8888 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008890 // If the slot was not found the result is true.
8891 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008892 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008893 }
8894
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008895 // If the slot was found in a context, it should be DONT_DELETE.
8896 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008897 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008898 }
8899
8900 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008901 // the global object, or the subject of a with. Try to delete it
8902 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008903 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008904 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008905}
8906
8907
ager@chromium.orga1645e22009-09-09 19:27:10 +00008908// A mechanism to return a pair of Object pointers in registers (if possible).
8909// How this is achieved is calling convention-dependent.
8910// All currently supported x86 compiles uses calling conventions that are cdecl
8911// variants where a 64-bit value is returned in two 32-bit registers
8912// (edx:eax on ia32, r1:r0 on ARM).
8913// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8914// In Win64 calling convention, a struct of two pointers is returned in memory,
8915// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008916#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008917struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008918 MaybeObject* x;
8919 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008920};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008921
lrn@chromium.org303ada72010-10-27 09:33:13 +00008922static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008923 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008924 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8925 // In Win64 they are assigned to a hidden first argument.
8926 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008927}
8928#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008929typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008930static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008931 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008932 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008933}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008934#endif
8935
8936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008937static inline MaybeObject* Unhole(Heap* heap,
8938 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008939 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8941 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008942 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008943}
8944
8945
danno@chromium.org40cb8782011-05-25 07:58:50 +00008946static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8947 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008948 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008950 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008951 JSFunction* context_extension_function =
8952 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008953 // If the holder isn't a context extension object, we just return it
8954 // as the receiver. This allows arguments objects to be used as
8955 // receivers, but only if they are put in the context scope chain
8956 // explicitly via a with-statement.
8957 Object* constructor = holder->map()->constructor();
8958 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008959 // Fall back to using the global object as the implicit receiver if
8960 // the property turns out to be a local variable allocated in a
8961 // context extension object - introduced via eval. Implicit global
8962 // receivers are indicated with the hole value.
8963 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008964}
8965
8966
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967static ObjectPair LoadContextSlotHelper(Arguments args,
8968 Isolate* isolate,
8969 bool throw_error) {
8970 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008971 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008973 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008974 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008977 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978
8979 int index;
8980 PropertyAttributes attributes;
8981 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008982 BindingFlags binding_flags;
8983 Handle<Object> holder = context->Lookup(name,
8984 flags,
8985 &index,
8986 &attributes,
8987 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008989 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008991 ASSERT(holder->IsContext());
8992 // If the "property" we were looking for is a local variable, the
8993 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008994 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008995 // Use the hole as the receiver to signal that the receiver is implicit
8996 // and that the global receiver should be used (as distinguished from an
8997 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008998 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008999 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009000 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009001 switch (binding_flags) {
9002 case MUTABLE_CHECK_INITIALIZED:
9003 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9004 if (value->IsTheHole()) {
9005 Handle<Object> reference_error =
9006 isolate->factory()->NewReferenceError("not_defined",
9007 HandleVector(&name, 1));
9008 return MakePair(isolate->Throw(*reference_error), NULL);
9009 }
9010 // FALLTHROUGH
9011 case MUTABLE_IS_INITIALIZED:
9012 case IMMUTABLE_IS_INITIALIZED:
9013 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9014 ASSERT(!value->IsTheHole());
9015 return MakePair(value, *receiver);
9016 case IMMUTABLE_CHECK_INITIALIZED:
9017 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9018 case MISSING_BINDING:
9019 UNREACHABLE();
9020 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009021 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009022 }
9023
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009024 // Otherwise, if the slot was found the holder is a context extension
9025 // object, subject of a with, or a global object. We read the named
9026 // property from it.
9027 if (!holder.is_null()) {
9028 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9029 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009030 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009031 Handle<Object> receiver_handle(object->IsGlobalObject()
9032 ? GlobalObject::cast(*object)->global_receiver()
9033 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009034
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009035 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009036 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009037 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009038 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039 }
9040
9041 if (throw_error) {
9042 // The property doesn't exist - throw exception.
9043 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009044 isolate->factory()->NewReferenceError("not_defined",
9045 HandleVector(&name, 1));
9046 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009048 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009049 return MakePair(isolate->heap()->undefined_value(),
9050 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009051 }
9052}
9053
9054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009055RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009056 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057}
9058
9059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009060RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009061 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062}
9063
9064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009065RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009066 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009067 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009069 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009071 CONVERT_ARG_CHECKED(String, name, 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009072 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073
9074 int index;
9075 PropertyAttributes attributes;
9076 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009077 BindingFlags binding_flags;
9078 Handle<Object> holder = context->Lookup(name,
9079 flags,
9080 &index,
9081 &attributes,
9082 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083
9084 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009085 // The property was found in a context slot.
9086 Handle<Context> context = Handle<Context>::cast(holder);
9087 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9088 context->get(index)->IsTheHole()) {
9089 Handle<Object> error =
9090 isolate->factory()->NewReferenceError("not_defined",
9091 HandleVector(&name, 1));
9092 return isolate->Throw(*error);
9093 }
9094 // Ignore if read_only variable.
9095 if ((attributes & READ_ONLY) == 0) {
9096 // Context is a fixed array and set cannot fail.
9097 context->set(index, *value);
9098 } else if (strict_mode == kStrictMode) {
9099 // Setting read only property in strict mode.
9100 Handle<Object> error =
9101 isolate->factory()->NewTypeError("strict_cannot_assign",
9102 HandleVector(&name, 1));
9103 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009104 }
9105 return *value;
9106 }
9107
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009108 // Slow case: The property is not in a context slot. It is either in a
9109 // context extension object, a property of the subject of a with, or a
9110 // property of the global object.
9111 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009112
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009113 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009114 // The property exists on the holder.
9115 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009116 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009117 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009119
9120 if (strict_mode == kStrictMode) {
9121 // Throw in strict mode (assignment to undefined variable).
9122 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009123 isolate->factory()->NewReferenceError(
9124 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009125 return isolate->Throw(*error);
9126 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009127 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009128 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009129 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009130 }
9131
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009132 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009133 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009134 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009135 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009137 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009138 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009139 // Setting read only property in strict mode.
9140 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 isolate->factory()->NewTypeError(
9142 "strict_cannot_assign", HandleVector(&name, 1));
9143 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009144 }
9145 return *value;
9146}
9147
9148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009149RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009150 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009151 ASSERT(args.length() == 1);
9152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009153 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009154}
9155
9156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009157RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 ASSERT(args.length() == 1);
9160
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009161 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162}
9163
9164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009165RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009166 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009167 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009168}
9169
9170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009171RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173 ASSERT(args.length() == 1);
9174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009175 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009177 isolate->factory()->NewReferenceError("not_defined",
9178 HandleVector(&name, 1));
9179 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180}
9181
9182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009183RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009184 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185
9186 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009187 if (isolate->stack_guard()->IsStackOverflow()) {
9188 NoHandleAllocation na;
9189 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009192 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009193}
9194
9195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009196static int StackSize() {
9197 int n = 0;
9198 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9199 return n;
9200}
9201
9202
9203static void PrintTransition(Object* result) {
9204 // indentation
9205 { const int nmax = 80;
9206 int n = StackSize();
9207 if (n <= nmax)
9208 PrintF("%4d:%*s", n, n, "");
9209 else
9210 PrintF("%4d:%*s", n, nmax, "...");
9211 }
9212
9213 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009214 JavaScriptFrame::PrintTop(stdout, true, false);
9215 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216 } else {
9217 // function result
9218 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009219 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220 PrintF("\n");
9221 }
9222}
9223
9224
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009225RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9226 ASSERT(args.length() == 5);
9227 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9228 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9229 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9230 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9231 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9232 NoHandleAllocation ha;
9233 PrintF("*");
9234 obj->PrintElementsTransition(stdout,
9235 static_cast<ElementsKind>(from_kind), *from_elements,
9236 static_cast<ElementsKind>(to_kind), *to_elements);
9237 return isolate->heap()->undefined_value();
9238}
9239
9240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009241RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009242 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009243 NoHandleAllocation ha;
9244 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246}
9247
9248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009249RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250 NoHandleAllocation ha;
9251 PrintTransition(args[0]);
9252 return args[0]; // return TOS
9253}
9254
9255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009256RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257 NoHandleAllocation ha;
9258 ASSERT(args.length() == 1);
9259
9260#ifdef DEBUG
9261 if (args[0]->IsString()) {
9262 // If we have a string, assume it's a code "marker"
9263 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009264 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009266 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9267 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009268 } else {
9269 PrintF("DebugPrint: ");
9270 }
9271 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009272 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009273 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009274 HeapObject::cast(args[0])->map()->Print();
9275 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009277 // ShortPrint is available in release mode. Print is not.
9278 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279#endif
9280 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009281 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009282
9283 return args[0]; // return TOS
9284}
9285
9286
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009287RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009288 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009290 isolate->PrintStack();
9291 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009292}
9293
9294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009295RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009296 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009297 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298
9299 // According to ECMA-262, section 15.9.1, page 117, the precision of
9300 // the number in a Date object representing a particular instant in
9301 // time is milliseconds. Therefore, we floor the result of getting
9302 // the OS time.
9303 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009304 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305}
9306
9307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009308RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009309 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009310 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009311
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009312 CONVERT_ARG_CHECKED(String, str, 0);
9313 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009314
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009315 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009316
9317 MaybeObject* maybe_result_array =
9318 output->EnsureCanContainNonSmiElements();
9319 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009320 RUNTIME_ASSERT(output->HasFastElements());
9321
9322 AssertNoAllocation no_allocation;
9323
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009324 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009325 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9326 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009327 String::FlatContent str_content = str->GetFlatContent();
9328 if (str_content.IsAscii()) {
9329 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009330 output_array,
9331 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009333 ASSERT(str_content.IsTwoByte());
9334 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009335 output_array,
9336 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009337 }
9338
9339 if (result) {
9340 return *output;
9341 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009342 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009343 }
9344}
9345
9346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009347RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348 NoHandleAllocation ha;
9349 ASSERT(args.length() == 1);
9350
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009351 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009352 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009354}
9355
9356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009357RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009359 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009361 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362}
9363
9364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009365RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009366 NoHandleAllocation ha;
9367 ASSERT(args.length() == 1);
9368
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009369 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009371}
9372
9373
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009374RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009375 ASSERT(args.length() == 1);
9376 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009378 return JSGlobalObject::cast(global)->global_receiver();
9379}
9380
9381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009382RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009383 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009384 ASSERT_EQ(1, args.length());
9385 CONVERT_ARG_CHECKED(String, source, 0);
9386
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009387 source = Handle<String>(source->TryFlattenGetString());
9388 // Optimized fast case where we only have ascii characters.
9389 Handle<Object> result;
9390 if (source->IsSeqAsciiString()) {
9391 result = JsonParser<true>::Parse(source);
9392 } else {
9393 result = JsonParser<false>::Parse(source);
9394 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009395 if (result.is_null()) {
9396 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009397 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009398 return Failure::Exception();
9399 }
9400 return *result;
9401}
9402
9403
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009404bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9405 Handle<Context> context) {
9406 if (context->allow_code_gen_from_strings()->IsFalse()) {
9407 // Check with callback if set.
9408 AllowCodeGenerationFromStringsCallback callback =
9409 isolate->allow_code_gen_callback();
9410 if (callback == NULL) {
9411 // No callback set and code generation disallowed.
9412 return false;
9413 } else {
9414 // Callback set. Let it decide if code generation is allowed.
9415 VMState state(isolate, EXTERNAL);
9416 return callback(v8::Utils::ToLocal(context));
9417 }
9418 }
9419 return true;
9420}
9421
9422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009423RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009424 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009425 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009426 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009427
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009428 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009429 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009430
9431 // Check if global context allows code generation from
9432 // strings. Throw an exception if it doesn't.
9433 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9434 return isolate->Throw(*isolate->factory()->NewError(
9435 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9436 }
9437
9438 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009439 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9440 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009441 true,
9442 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009443 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009445 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9446 context,
9447 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009448 return *fun;
9449}
9450
9451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009452static ObjectPair CompileGlobalEval(Isolate* isolate,
9453 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009454 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009455 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009456 Handle<Context> context = Handle<Context>(isolate->context());
9457 Handle<Context> global_context = Handle<Context>(context->global_context());
9458
9459 // Check if global context allows code generation from
9460 // strings. Throw an exception if it doesn't.
9461 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9462 isolate->Throw(*isolate->factory()->NewError(
9463 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9464 return MakePair(Failure::Exception(), NULL);
9465 }
9466
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009467 // Deal with a normal eval call with a string argument. Compile it
9468 // and return the compiled function bound in the local context.
9469 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9470 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009472 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009473 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009474 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 Handle<JSFunction> compiled =
9476 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009477 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009478 return MakePair(*compiled, *receiver);
9479}
9480
9481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009482RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009483 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009485 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009486 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009487
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009488 // If "eval" didn't refer to the original GlobalEval, it's not a
9489 // direct call to eval.
9490 // (And even if it is, but the first argument isn't a string, just let
9491 // execution default to an indirect call to eval, which will also return
9492 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009493 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009494 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009495 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009496 }
9497
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009498 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009499 return CompileGlobalEval(isolate,
9500 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009501 args.at<Object>(2),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009502 strict_mode);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009503}
9504
9505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009506RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009507 // This utility adjusts the property attributes for newly created Function
9508 // object ("new Function(...)") by changing the map.
9509 // All it does is changing the prototype property to enumerable
9510 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009512 ASSERT(args.length() == 1);
9513 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009514
9515 Handle<Map> map = func->shared()->strict_mode()
9516 ? isolate->strict_mode_function_instance_map()
9517 : isolate->function_instance_map();
9518
9519 ASSERT(func->map()->instance_type() == map->instance_type());
9520 ASSERT(func->map()->instance_size() == map->instance_size());
9521 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009522 return *func;
9523}
9524
9525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009526RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009527 // Allocate a block of memory in NewSpace (filled with a filler).
9528 // Use as fallback for allocation in generated code when NewSpace
9529 // is full.
9530 ASSERT(args.length() == 1);
9531 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9532 int size = size_smi->value();
9533 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9534 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009535 Heap* heap = isolate->heap();
9536 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009537 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009538 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009540 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009542 }
9543 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009544 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009545}
9546
9547
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009548// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009549// array. Returns true if the element was pushed on the stack and
9550// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009551RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009552 ASSERT(args.length() == 2);
9553 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009554 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009555 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009556 int length = Smi::cast(array->length())->value();
9557 FixedArray* elements = FixedArray::cast(array->elements());
9558 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009559 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009560 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009561 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009562 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009563 { MaybeObject* maybe_obj =
9564 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009565 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009567 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009568}
9569
9570
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009571/**
9572 * A simple visitor visits every element of Array's.
9573 * The backend storage can be a fixed array for fast elements case,
9574 * or a dictionary for sparse array. Since Dictionary is a subtype
9575 * of FixedArray, the class can be used by both fast and slow cases.
9576 * The second parameter of the constructor, fast_elements, specifies
9577 * whether the storage is a FixedArray or Dictionary.
9578 *
9579 * An index limit is used to deal with the situation that a result array
9580 * length overflows 32-bit non-negative integer.
9581 */
9582class ArrayConcatVisitor {
9583 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 ArrayConcatVisitor(Isolate* isolate,
9585 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009586 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009587 isolate_(isolate),
9588 storage_(Handle<FixedArray>::cast(
9589 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009590 index_offset_(0u),
9591 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009592
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009593 ~ArrayConcatVisitor() {
9594 clear_storage();
9595 }
9596
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009597 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009599 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009600
9601 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009602 if (index < static_cast<uint32_t>(storage_->length())) {
9603 storage_->set(index, *elm);
9604 return;
9605 }
9606 // Our initial estimate of length was foiled, possibly by
9607 // getters on the arrays increasing the length of later arrays
9608 // during iteration.
9609 // This shouldn't happen in anything but pathological cases.
9610 SetDictionaryMode(index);
9611 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009612 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009613 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009614 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009615 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009616 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009617 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009618 // Dictionary needed to grow.
9619 clear_storage();
9620 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009621 }
9622}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009623
9624 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009625 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9626 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009627 } else {
9628 index_offset_ += delta;
9629 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009630 }
9631
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009632 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009633 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009634 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009636 Handle<Map> map;
9637 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009638 map = isolate_->factory()->GetElementsTransitionMap(array,
9639 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009640 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009641 map = isolate_->factory()->GetElementsTransitionMap(array,
9642 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 }
9644 array->set_map(*map);
9645 array->set_length(*length);
9646 array->set_elements(*storage_);
9647 return array;
9648 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009649
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009650 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009651 // Convert storage to dictionary mode.
9652 void SetDictionaryMode(uint32_t index) {
9653 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009654 Handle<FixedArray> current_storage(*storage_);
9655 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009656 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9658 for (uint32_t i = 0; i < current_length; i++) {
9659 HandleScope loop_scope;
9660 Handle<Object> element(current_storage->get(i));
9661 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009662 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009663 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009664 if (!new_storage.is_identical_to(slow_storage)) {
9665 slow_storage = loop_scope.CloseAndEscape(new_storage);
9666 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009667 }
9668 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009669 clear_storage();
9670 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 fast_elements_ = false;
9672 }
9673
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009674 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009675 isolate_->global_handles()->Destroy(
9676 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009677 }
9678
9679 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009680 storage_ = Handle<FixedArray>::cast(
9681 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009682 }
9683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009685 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009686 // Index after last seen index. Always less than or equal to
9687 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009688 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009689 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009690};
9691
9692
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693static uint32_t EstimateElementCount(Handle<JSArray> array) {
9694 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9695 int element_count = 0;
9696 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009697 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009698 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699 // Fast elements can't have lengths that are not representable by
9700 // a 32-bit signed integer.
9701 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9702 int fast_length = static_cast<int>(length);
9703 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9704 for (int i = 0; i < fast_length; i++) {
9705 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009706 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009707 break;
9708 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009709 case FAST_DOUBLE_ELEMENTS:
9710 // TODO(1810): Decide if it's worthwhile to implement this.
9711 UNREACHABLE();
9712 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009713 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 Handle<NumberDictionary> dictionary(
9715 NumberDictionary::cast(array->elements()));
9716 int capacity = dictionary->Capacity();
9717 for (int i = 0; i < capacity; i++) {
9718 Handle<Object> key(dictionary->KeyAt(i));
9719 if (dictionary->IsKey(*key)) {
9720 element_count++;
9721 }
9722 }
9723 break;
9724 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009725 case NON_STRICT_ARGUMENTS_ELEMENTS:
9726 case EXTERNAL_BYTE_ELEMENTS:
9727 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9728 case EXTERNAL_SHORT_ELEMENTS:
9729 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9730 case EXTERNAL_INT_ELEMENTS:
9731 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9732 case EXTERNAL_FLOAT_ELEMENTS:
9733 case EXTERNAL_DOUBLE_ELEMENTS:
9734 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 // External arrays are always dense.
9736 return length;
9737 }
9738 // As an estimate, we assume that the prototype doesn't contain any
9739 // inherited elements.
9740 return element_count;
9741}
9742
9743
9744
9745template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009746static void IterateExternalArrayElements(Isolate* isolate,
9747 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 bool elements_are_ints,
9749 bool elements_are_guaranteed_smis,
9750 ArrayConcatVisitor* visitor) {
9751 Handle<ExternalArrayClass> array(
9752 ExternalArrayClass::cast(receiver->elements()));
9753 uint32_t len = static_cast<uint32_t>(array->length());
9754
9755 ASSERT(visitor != NULL);
9756 if (elements_are_ints) {
9757 if (elements_are_guaranteed_smis) {
9758 for (uint32_t j = 0; j < len; j++) {
9759 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009760 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009761 visitor->visit(j, e);
9762 }
9763 } else {
9764 for (uint32_t j = 0; j < len; j++) {
9765 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009766 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9768 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9769 visitor->visit(j, e);
9770 } else {
9771 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 visitor->visit(j, e);
9774 }
9775 }
9776 }
9777 } else {
9778 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009780 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009781 visitor->visit(j, e);
9782 }
9783 }
9784}
9785
9786
9787// Used for sorting indices in a List<uint32_t>.
9788static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9789 uint32_t a = *ap;
9790 uint32_t b = *bp;
9791 return (a == b) ? 0 : (a < b) ? -1 : 1;
9792}
9793
9794
9795static void CollectElementIndices(Handle<JSObject> object,
9796 uint32_t range,
9797 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009798 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009799 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009800 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009801 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009802 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9803 uint32_t length = static_cast<uint32_t>(elements->length());
9804 if (range < length) length = range;
9805 for (uint32_t i = 0; i < length; i++) {
9806 if (!elements->get(i)->IsTheHole()) {
9807 indices->Add(i);
9808 }
9809 }
9810 break;
9811 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009812 case FAST_DOUBLE_ELEMENTS: {
9813 // TODO(1810): Decide if it's worthwhile to implement this.
9814 UNREACHABLE();
9815 break;
9816 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009817 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009819 uint32_t capacity = dict->Capacity();
9820 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009821 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009822 Handle<Object> k(dict->KeyAt(j));
9823 if (dict->IsKey(*k)) {
9824 ASSERT(k->IsNumber());
9825 uint32_t index = static_cast<uint32_t>(k->Number());
9826 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009827 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009828 }
9829 }
9830 }
9831 break;
9832 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009833 default: {
9834 int dense_elements_length;
9835 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009836 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009837 dense_elements_length =
9838 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 break;
9840 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009841 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009842 dense_elements_length =
9843 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009844 break;
9845 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009846 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009847 dense_elements_length =
9848 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 break;
9850 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009851 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009852 dense_elements_length =
9853 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 break;
9855 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009856 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009857 dense_elements_length =
9858 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 break;
9860 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009861 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009862 dense_elements_length =
9863 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009864 break;
9865 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009866 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009867 dense_elements_length =
9868 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009869 break;
9870 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009871 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009872 dense_elements_length =
9873 ExternalFloatArray::cast(object->elements())->length();
9874 break;
9875 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009876 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009877 dense_elements_length =
9878 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009879 break;
9880 }
9881 default:
9882 UNREACHABLE();
9883 dense_elements_length = 0;
9884 break;
9885 }
9886 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9887 if (range <= length) {
9888 length = range;
9889 // We will add all indices, so we might as well clear it first
9890 // and avoid duplicates.
9891 indices->Clear();
9892 }
9893 for (uint32_t i = 0; i < length; i++) {
9894 indices->Add(i);
9895 }
9896 if (length == range) return; // All indices accounted for already.
9897 break;
9898 }
9899 }
9900
9901 Handle<Object> prototype(object->GetPrototype());
9902 if (prototype->IsJSObject()) {
9903 // The prototype will usually have no inherited element indices,
9904 // but we have to check.
9905 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9906 }
9907}
9908
9909
9910/**
9911 * A helper function that visits elements of a JSArray in numerical
9912 * order.
9913 *
9914 * The visitor argument called for each existing element in the array
9915 * with the element index and the element's value.
9916 * Afterwards it increments the base-index of the visitor by the array
9917 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009918 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009919 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009920static bool IterateElements(Isolate* isolate,
9921 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 ArrayConcatVisitor* visitor) {
9923 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9924 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009925 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009926 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 // Run through the elements FixedArray and use HasElement and GetElement
9928 // to check the prototype for missing elements.
9929 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9930 int fast_length = static_cast<int>(length);
9931 ASSERT(fast_length <= elements->length());
9932 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009933 HandleScope loop_scope(isolate);
9934 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009935 if (!element_value->IsTheHole()) {
9936 visitor->visit(j, element_value);
9937 } else if (receiver->HasElement(j)) {
9938 // Call GetElement on receiver, not its prototype, or getters won't
9939 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009940 element_value = Object::GetElement(receiver, j);
9941 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009942 visitor->visit(j, element_value);
9943 }
9944 }
9945 break;
9946 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009947 case FAST_DOUBLE_ELEMENTS: {
9948 // TODO(1810): Decide if it's worthwhile to implement this.
9949 UNREACHABLE();
9950 break;
9951 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009952 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009953 Handle<NumberDictionary> dict(receiver->element_dictionary());
9954 List<uint32_t> indices(dict->Capacity() / 2);
9955 // Collect all indices in the object and the prototypes less
9956 // than length. This might introduce duplicates in the indices list.
9957 CollectElementIndices(receiver, length, &indices);
9958 indices.Sort(&compareUInt32);
9959 int j = 0;
9960 int n = indices.length();
9961 while (j < n) {
9962 HandleScope loop_scope;
9963 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009964 Handle<Object> element = Object::GetElement(receiver, index);
9965 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009966 visitor->visit(index, element);
9967 // Skip to next different index (i.e., omit duplicates).
9968 do {
9969 j++;
9970 } while (j < n && indices[j] == index);
9971 }
9972 break;
9973 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009974 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009975 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9976 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009977 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009978 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009979 visitor->visit(j, e);
9980 }
9981 break;
9982 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009983 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 break;
9992 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009993 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 break;
9997 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009998 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010001 break;
10002 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010003 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010005 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010006 break;
10007 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010008 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010009 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010011 break;
10012 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010013 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010014 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010015 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010016 break;
10017 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010018 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010019 IterateExternalArrayElements<ExternalDoubleArray, double>(
10020 isolate, receiver, false, false, visitor);
10021 break;
10022 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010023 default:
10024 UNREACHABLE();
10025 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010026 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010028 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010029}
10030
10031
10032/**
10033 * Array::concat implementation.
10034 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010035 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010036 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010037 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010038RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010039 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010040 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010041
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10043 int argument_count = static_cast<int>(arguments->length()->Number());
10044 RUNTIME_ASSERT(arguments->HasFastElements());
10045 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010046
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 // Pass 1: estimate the length and number of elements of the result.
10048 // The actual length can be larger if any of the arguments have getters
10049 // that mutate other arguments (but will otherwise be precise).
10050 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010051
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 uint32_t estimate_result_length = 0;
10053 uint32_t estimate_nof_elements = 0;
10054 {
10055 for (int i = 0; i < argument_count; i++) {
10056 HandleScope loop_scope;
10057 Handle<Object> obj(elements->get(i));
10058 uint32_t length_estimate;
10059 uint32_t element_estimate;
10060 if (obj->IsJSArray()) {
10061 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010062 // TODO(1810): Find out if it's worthwhile to properly support
10063 // arbitrary ElementsKinds. For now, pessimistically transition to
10064 // FAST_ELEMENTS.
10065 if (array->HasFastDoubleElements()) {
10066 array = Handle<JSArray>::cast(
10067 TransitionElementsKind(array, FAST_ELEMENTS));
10068 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010069 length_estimate =
10070 static_cast<uint32_t>(array->length()->Number());
10071 element_estimate =
10072 EstimateElementCount(array);
10073 } else {
10074 length_estimate = 1;
10075 element_estimate = 1;
10076 }
10077 // Avoid overflows by capping at kMaxElementCount.
10078 if (JSObject::kMaxElementCount - estimate_result_length <
10079 length_estimate) {
10080 estimate_result_length = JSObject::kMaxElementCount;
10081 } else {
10082 estimate_result_length += length_estimate;
10083 }
10084 if (JSObject::kMaxElementCount - estimate_nof_elements <
10085 element_estimate) {
10086 estimate_nof_elements = JSObject::kMaxElementCount;
10087 } else {
10088 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010089 }
10090 }
10091 }
10092
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010093 // If estimated number of elements is more than half of length, a
10094 // fixed array (fast case) is more time and space-efficient than a
10095 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010096 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010097
10098 Handle<FixedArray> storage;
10099 if (fast_case) {
10100 // The backing storage array must have non-existing elements to
10101 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 storage = isolate->factory()->NewFixedArrayWithHoles(
10103 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010104 } else {
10105 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10106 uint32_t at_least_space_for = estimate_nof_elements +
10107 (estimate_nof_elements >> 2);
10108 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010110 }
10111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010112 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010113
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010114 for (int i = 0; i < argument_count; i++) {
10115 Handle<Object> obj(elements->get(i));
10116 if (obj->IsJSArray()) {
10117 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010119 return Failure::Exception();
10120 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010121 } else {
10122 visitor.visit(0, obj);
10123 visitor.increase_index_offset(1);
10124 }
10125 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010126
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010127 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010128}
10129
10130
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010131// This will not allocate (flatten the string), but it may run
10132// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010133RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134 NoHandleAllocation ha;
10135 ASSERT(args.length() == 1);
10136
10137 CONVERT_CHECKED(String, string, args[0]);
10138 StringInputBuffer buffer(string);
10139 while (buffer.has_more()) {
10140 uint16_t character = buffer.GetNext();
10141 PrintF("%c", character);
10142 }
10143 return string;
10144}
10145
ager@chromium.org5ec48922009-05-05 07:25:34 +000010146// Moves all own elements of an object, that are below a limit, to positions
10147// starting at zero. All undefined values are placed after non-undefined values,
10148// and are followed by non-existing element. Does not change the length
10149// property.
10150// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010151RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010152 ASSERT(args.length() == 2);
10153 CONVERT_CHECKED(JSObject, object, args[0]);
10154 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10155 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010156}
10157
10158
10159// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010160RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010161 ASSERT(args.length() == 2);
10162 CONVERT_CHECKED(JSArray, from, args[0]);
10163 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010164 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010165 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010166 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010167 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10168 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010169 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010170 } else if (new_elements->map() ==
10171 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010172 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010173 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010174 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010175 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010176 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010177 Object* new_map;
10178 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010179 to->set_map(Map::cast(new_map));
10180 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010182 Object* obj;
10183 { MaybeObject* maybe_obj = from->ResetElements();
10184 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10185 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010186 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 return to;
10188}
10189
10190
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010191// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010192RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010193 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010194 CONVERT_CHECKED(JSObject, object, args[0]);
10195 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010197 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010198 } else if (object->IsJSArray()) {
10199 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010201 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010202 }
10203}
10204
10205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010206RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010207 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010208
10209 ASSERT_EQ(3, args.length());
10210
ager@chromium.orgac091b72010-05-05 07:34:42 +000010211 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010212 Handle<Object> key1 = args.at<Object>(1);
10213 Handle<Object> key2 = args.at<Object>(2);
10214
10215 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010216 if (!key1->ToArrayIndex(&index1)
10217 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010219 }
10220
ager@chromium.orgac091b72010-05-05 07:34:42 +000010221 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010222 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010223 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010224 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 RETURN_IF_EMPTY_HANDLE(isolate,
10228 SetElement(jsobject, index1, tmp2, kStrictMode));
10229 RETURN_IF_EMPTY_HANDLE(isolate,
10230 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010233}
10234
10235
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010237// might have elements. Can either return keys (positive integers) or
10238// intervals (pair of a negative integer (-start-1) followed by a
10239// positive (length)) or undefined values.
10240// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010241RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010243 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010244 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010246 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010247 // Create an array and get all the keys into it, then remove all the
10248 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010249 bool threw = false;
10250 Handle<FixedArray> keys =
10251 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10252 if (threw) return Failure::Exception();
10253
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 int keys_length = keys->length();
10255 for (int i = 0; i < keys_length; i++) {
10256 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010257 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010258 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259 // Zap invalid keys.
10260 keys->set_undefined(i);
10261 }
10262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010263 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010265 ASSERT(array->HasFastElements() ||
10266 array->HasFastSmiOnlyElements() ||
10267 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010268 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010270 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010271 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010272 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010273 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010274 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010276 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010278 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 }
10280}
10281
10282
10283// DefineAccessor takes an optional final argument which is the
10284// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10285// to the way accessors are implemented, it is set for both the getter
10286// and setter on the first call to DefineAccessor and ignored on
10287// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010288RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10290 // Compute attributes.
10291 PropertyAttributes attributes = NONE;
10292 if (args.length() == 5) {
10293 CONVERT_CHECKED(Smi, attrs, args[4]);
10294 int value = attrs->value();
10295 // Only attribute bits should be set.
10296 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10297 attributes = static_cast<PropertyAttributes>(value);
10298 }
10299
10300 CONVERT_CHECKED(JSObject, obj, args[0]);
10301 CONVERT_CHECKED(String, name, args[1]);
10302 CONVERT_CHECKED(Smi, flag, args[2]);
10303 CONVERT_CHECKED(JSFunction, fun, args[3]);
10304 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10305}
10306
10307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010308RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 ASSERT(args.length() == 3);
10310 CONVERT_CHECKED(JSObject, obj, args[0]);
10311 CONVERT_CHECKED(String, name, args[1]);
10312 CONVERT_CHECKED(Smi, flag, args[2]);
10313 return obj->LookupAccessor(name, flag->value() == 0);
10314}
10315
10316
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010317#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010318RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010319 ASSERT(args.length() == 0);
10320 return Execution::DebugBreakHelper();
10321}
10322
10323
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324// Helper functions for wrapping and unwrapping stack frame ids.
10325static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010326 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327 return Smi::FromInt(id >> 2);
10328}
10329
10330
10331static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10332 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10333}
10334
10335
10336// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010337// args[0]: debug event listener function to set or null or undefined for
10338// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010340RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010342 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10343 args[0]->IsUndefined() ||
10344 args[0]->IsNull());
10345 Handle<Object> callback = args.at<Object>(0);
10346 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010349 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350}
10351
10352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010353RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010354 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 isolate->stack_guard()->DebugBreak();
10356 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357}
10358
10359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010360static MaybeObject* DebugLookupResultValue(Heap* heap,
10361 Object* receiver,
10362 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010363 LookupResult* result,
10364 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010365 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010367 case NORMAL:
10368 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010369 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371 }
10372 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010373 case FIELD:
10374 value =
10375 JSObject::cast(
10376 result->holder())->FastPropertyAt(result->GetFieldIndex());
10377 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010378 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010379 }
10380 return value;
10381 case CONSTANT_FUNCTION:
10382 return result->GetConstantFunction();
10383 case CALLBACKS: {
10384 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010385 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010386 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10387 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010388 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010389 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010390 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 maybe_value = heap->isolate()->pending_exception();
10392 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010393 if (caught_exception != NULL) {
10394 *caught_exception = true;
10395 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010396 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010397 }
10398 return value;
10399 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010400 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010401 }
10402 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010404 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010405 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010406 case CONSTANT_TRANSITION:
10407 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010408 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010409 default:
10410 UNREACHABLE();
10411 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010412 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010413 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414}
10415
10416
ager@chromium.org32912102009-01-16 10:38:43 +000010417// Get debugger related details for an object property.
10418// args[0]: object holding property
10419// args[1]: name of the property
10420//
10421// The array returned contains the following information:
10422// 0: Property value
10423// 1: Property details
10424// 2: Property value is exception
10425// 3: Getter function if defined
10426// 4: Setter function if defined
10427// Items 2-4 are only filled if the property has either a getter or a setter
10428// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010429RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010430 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010431
10432 ASSERT(args.length() == 2);
10433
10434 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10435 CONVERT_ARG_CHECKED(String, name, 1);
10436
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010437 // Make sure to set the current context to the context before the debugger was
10438 // entered (if the debugger is entered). The reason for switching context here
10439 // is that for some property lookups (accessors and interceptors) callbacks
10440 // into the embedding application can occour, and the embedding application
10441 // could have the assumption that its own global context is the current
10442 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010443 SaveContext save(isolate);
10444 if (isolate->debug()->InDebugger()) {
10445 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010446 }
10447
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010448 // Skip the global proxy as it has no properties and always delegates to the
10449 // real global object.
10450 if (obj->IsJSGlobalProxy()) {
10451 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10452 }
10453
10454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 // Check if the name is trivially convertible to an index and get the element
10456 // if so.
10457 uint32_t index;
10458 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010459 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010460 Object* element_or_char;
10461 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010463 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10464 return maybe_element_or_char;
10465 }
10466 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010467 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010468 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010470 }
10471
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010472 // Find the number of objects making up this.
10473 int length = LocalPrototypeChainLength(*obj);
10474
10475 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010476 Handle<JSObject> jsproto = obj;
10477 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010478 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010479 jsproto->LocalLookup(*name, &result);
10480 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010481 // LookupResult is not GC safe as it holds raw object pointers.
10482 // GC can happen later in this code so put the required fields into
10483 // local variables using handles when required for later use.
10484 PropertyType result_type = result.type();
10485 Handle<Object> result_callback_obj;
10486 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010487 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10488 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010489 }
10490 Smi* property_details = result.GetPropertyDetails().AsSmi();
10491 // DebugLookupResultValue can cause GC so details from LookupResult needs
10492 // to be copied to handles before this.
10493 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010494 Object* raw_value;
10495 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496 DebugLookupResultValue(isolate->heap(), *obj, *name,
10497 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010498 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10499 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010500 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010501
10502 // If the callback object is a fixed array then it contains JavaScript
10503 // getter and/or setter.
10504 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10505 result_callback_obj->IsFixedArray();
10506 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010508 details->set(0, *value);
10509 details->set(1, property_details);
10510 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010511 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010512 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10513 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10514 }
10515
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010516 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010517 }
10518 if (i < length - 1) {
10519 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10520 }
10521 }
10522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524}
10525
10526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010527RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010528 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529
10530 ASSERT(args.length() == 2);
10531
10532 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10533 CONVERT_ARG_CHECKED(String, name, 1);
10534
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010535 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010536 obj->Lookup(*name, &result);
10537 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010538 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010539 }
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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544// Return the property type calculated from the property details.
10545// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010546RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010547 ASSERT(args.length() == 1);
10548 CONVERT_CHECKED(Smi, details, args[0]);
10549 PropertyType type = PropertyDetails(details).type();
10550 return Smi::FromInt(static_cast<int>(type));
10551}
10552
10553
10554// Return the property attribute calculated from the property details.
10555// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010556RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 ASSERT(args.length() == 1);
10558 CONVERT_CHECKED(Smi, details, args[0]);
10559 PropertyAttributes attributes = PropertyDetails(details).attributes();
10560 return Smi::FromInt(static_cast<int>(attributes));
10561}
10562
10563
10564// Return the property insertion index calculated from the property details.
10565// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010566RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 ASSERT(args.length() == 1);
10568 CONVERT_CHECKED(Smi, details, args[0]);
10569 int index = PropertyDetails(details).index();
10570 return Smi::FromInt(index);
10571}
10572
10573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574// Return property value from named interceptor.
10575// args[0]: object
10576// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010577RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579 ASSERT(args.length() == 2);
10580 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10581 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10582 CONVERT_ARG_CHECKED(String, name, 1);
10583
10584 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010585 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586}
10587
10588
10589// Return element value from indexed interceptor.
10590// args[0]: object
10591// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010592RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594 ASSERT(args.length() == 2);
10595 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10596 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10597 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10598
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010599 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600}
10601
10602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010603RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604 ASSERT(args.length() >= 1);
10605 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010606 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 if (isolate->debug()->break_id() == 0 ||
10608 break_id != isolate->debug()->break_id()) {
10609 return isolate->Throw(
10610 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 }
10612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010613 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614}
10615
10616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010617RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010618 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619 ASSERT(args.length() == 1);
10620
10621 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010622 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010623 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10624 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010625 if (!maybe_result->ToObject(&result)) return maybe_result;
10626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627
10628 // Count all frames which are relevant to debugging stack trace.
10629 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010630 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010631 if (id == StackFrame::NO_ID) {
10632 // If there is no JavaScript stack frame count is 0.
10633 return Smi::FromInt(0);
10634 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010635
10636 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10637 n += it.frame()->GetInlineCount();
10638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 return Smi::FromInt(n);
10640}
10641
10642
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010643class FrameInspector {
10644 public:
10645 FrameInspector(JavaScriptFrame* frame,
10646 int inlined_frame_index,
10647 Isolate* isolate)
10648 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10649 // Calculate the deoptimized frame.
10650 if (frame->is_optimized()) {
10651 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10652 frame, inlined_frame_index, isolate);
10653 }
10654 has_adapted_arguments_ = frame_->has_adapted_arguments();
10655 is_optimized_ = frame_->is_optimized();
10656 }
10657
10658 ~FrameInspector() {
10659 // Get rid of the calculated deoptimized frame if any.
10660 if (deoptimized_frame_ != NULL) {
10661 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10662 isolate_);
10663 }
10664 }
10665
10666 int GetParametersCount() {
10667 return is_optimized_
10668 ? deoptimized_frame_->parameters_count()
10669 : frame_->ComputeParametersCount();
10670 }
10671 int expression_count() { return deoptimized_frame_->expression_count(); }
10672 Object* GetFunction() {
10673 return is_optimized_
10674 ? deoptimized_frame_->GetFunction()
10675 : frame_->function();
10676 }
10677 Object* GetParameter(int index) {
10678 return is_optimized_
10679 ? deoptimized_frame_->GetParameter(index)
10680 : frame_->GetParameter(index);
10681 }
10682 Object* GetExpression(int index) {
10683 return is_optimized_
10684 ? deoptimized_frame_->GetExpression(index)
10685 : frame_->GetExpression(index);
10686 }
10687
10688 // To inspect all the provided arguments the frame might need to be
10689 // replaced with the arguments frame.
10690 void SetArgumentsFrame(JavaScriptFrame* frame) {
10691 ASSERT(has_adapted_arguments_);
10692 frame_ = frame;
10693 is_optimized_ = frame_->is_optimized();
10694 ASSERT(!is_optimized_);
10695 }
10696
10697 private:
10698 JavaScriptFrame* frame_;
10699 DeoptimizedFrameInfo* deoptimized_frame_;
10700 Isolate* isolate_;
10701 bool is_optimized_;
10702 bool has_adapted_arguments_;
10703
10704 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10705};
10706
10707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010708static const int kFrameDetailsFrameIdIndex = 0;
10709static const int kFrameDetailsReceiverIndex = 1;
10710static const int kFrameDetailsFunctionIndex = 2;
10711static const int kFrameDetailsArgumentCountIndex = 3;
10712static const int kFrameDetailsLocalCountIndex = 4;
10713static const int kFrameDetailsSourcePositionIndex = 5;
10714static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010715static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010716static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010717static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010719
10720static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10721 JavaScriptFrame* frame) {
10722 SaveContext* save = isolate->save_context();
10723 while (save != NULL && !save->IsBelowFrame(frame)) {
10724 save = save->prev();
10725 }
10726 ASSERT(save != NULL);
10727 return save;
10728}
10729
10730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731// Return an array with frame details
10732// args[0]: number: break id
10733// args[1]: number: frame index
10734//
10735// The array returned contains the following information:
10736// 0: Frame id
10737// 1: Receiver
10738// 2: Function
10739// 3: Argument count
10740// 4: Local count
10741// 5: Source position
10742// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010743// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010744// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745// Arguments name, value
10746// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010747// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010748RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010749 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010750 ASSERT(args.length() == 2);
10751
10752 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010753 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010754 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10755 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010756 if (!maybe_check->ToObject(&check)) return maybe_check;
10757 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010759 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760
10761 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010763 if (id == StackFrame::NO_ID) {
10764 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010765 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010766 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010767
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010768 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010769
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010771 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010773 if (index < count + it.frame()->GetInlineCount()) break;
10774 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010776 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010778 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010779 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010780 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010781 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010782 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010783
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010784 // Traverse the saved contexts chain to find the active context for the
10785 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010786 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787
10788 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010789 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790
10791 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010793 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010795 // Check for constructor frame. Inlined frames cannot be construct calls.
10796 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010797 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010798 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010800 // Get scope info and read from it for local variable information.
10801 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010802 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010803 Handle<ScopeInfo> scope_info(shared->scope_info());
10804 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806 // Get the locals names and values into a temporary array.
10807 //
10808 // TODO(1240907): Hide compiler-introduced stack variables
10809 // (e.g. .result)? For users of the debugger, they will probably be
10810 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010811 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010812 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010813
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010814 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010815 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010816 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010817 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010818 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010819 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010820 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010821 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010822 // Get the context containing declarations.
10823 Handle<Context> context(
10824 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010825 for (; i < scope_info->LocalCount(); ++i) {
10826 Handle<String> name(scope_info->LocalName(i));
10827 VariableMode mode;
10828 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010829 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010830 locals->set(i * 2 + 1, context->get(
10831 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832 }
10833 }
10834
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010835 // Check whether this frame is positioned at return. If not top
10836 // frame or if the frame is optimized it cannot be at a return.
10837 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010838 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010839 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010840 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010841
10842 // If positioned just before return find the value to be returned and add it
10843 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010844 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010845 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010846 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010847 Address internal_frame_sp = NULL;
10848 while (!it2.done()) {
10849 if (it2.frame()->is_internal()) {
10850 internal_frame_sp = it2.frame()->sp();
10851 } else {
10852 if (it2.frame()->is_java_script()) {
10853 if (it2.frame()->id() == it.frame()->id()) {
10854 // The internal frame just before the JavaScript frame contains the
10855 // value to return on top. A debug break at return will create an
10856 // internal frame to store the return value (eax/rax/r0) before
10857 // entering the debug break exit frame.
10858 if (internal_frame_sp != NULL) {
10859 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010860 Handle<Object>(Memory::Object_at(internal_frame_sp),
10861 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010862 break;
10863 }
10864 }
10865 }
10866
10867 // Indicate that the previous frame was not an internal frame.
10868 internal_frame_sp = NULL;
10869 }
10870 it2.Advance();
10871 }
10872 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873
10874 // Now advance to the arguments adapter frame (if any). It contains all
10875 // the provided parameters whereas the function frame always have the number
10876 // of arguments matching the functions parameters. The rest of the
10877 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010878 if (it.frame()->has_adapted_arguments()) {
10879 it.AdvanceToArgumentsFrame();
10880 frame_inspector.SetArgumentsFrame(it.frame());
10881 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010882
10883 // Find the number of arguments to fill. At least fill the number of
10884 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010885 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010886 if (argument_count < frame_inspector.GetParametersCount()) {
10887 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010889#ifdef DEBUG
10890 if (it.frame()->is_optimized()) {
10891 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10892 }
10893#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010894
10895 // Calculate the size of the result.
10896 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010897 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010898 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010899 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900
10901 // Add the frame id.
10902 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10903
10904 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010905 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010906
10907 // Add the arguments count.
10908 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10909
10910 // Add the locals count
10911 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010912 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010913
10914 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010915 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10917 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010918 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919 }
10920
10921 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010923
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010924 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010925 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010926
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010927 // Add flags to indicate information on whether this frame is
10928 // bit 0: invoked in the debugger context.
10929 // bit 1: optimized frame.
10930 // bit 2: inlined in optimized frame
10931 int flags = 0;
10932 if (*save->context() == *isolate->debug()->debug_context()) {
10933 flags |= 1 << 0;
10934 }
10935 if (it.frame()->is_optimized()) {
10936 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010937 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010938 }
10939 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940
10941 // Fill the dynamic part.
10942 int details_index = kFrameDetailsFirstDynamicIndex;
10943
10944 // Add arguments name and value.
10945 for (int i = 0; i < argument_count; i++) {
10946 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010947 if (i < scope_info->ParameterCount()) {
10948 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951 }
10952
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010953 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010954 if (i < it.frame()->ComputeParametersCount()) {
10955 // Get the value from the stack.
10956 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010957 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010958 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 }
10960 }
10961
10962 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010963 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010964 details->set(details_index++, locals->get(i));
10965 }
10966
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010967 // Add the value being returned.
10968 if (at_return) {
10969 details->set(details_index++, *return_value);
10970 }
10971
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010972 // Add the receiver (same as in function frame).
10973 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10974 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010976 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10977 // If the receiver is not a JSObject and the function is not a
10978 // builtin or strict-mode we have hit an optimization where a
10979 // value object is not converted into a wrapped JS objects. To
10980 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981 // by creating correct wrapper object based on the calling frame's
10982 // global context.
10983 it.Advance();
10984 Handle<Context> calling_frames_global_context(
10985 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010986 receiver =
10987 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010988 }
10989 details->set(kFrameDetailsReceiverIndex, *receiver);
10990
10991 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010992 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993}
10994
10995
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010996// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010997static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010999 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011000 Handle<Context> context,
11001 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011002 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011003 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11004 VariableMode mode;
11005 InitializationFlag init_flag;
11006 int context_index = scope_info->ContextSlotIndex(
11007 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011008
whesse@chromium.org7b260152011-06-20 15:33:18 +000011009 RETURN_IF_EMPTY_HANDLE_VALUE(
11010 isolate,
11011 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011012 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011013 Handle<Object>(context->get(context_index), isolate),
11014 NONE,
11015 kNonStrictMode),
11016 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011018
11019 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011020}
11021
11022
11023// Create a plain JSObject which materializes the local scope for the specified
11024// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011025static Handle<JSObject> MaterializeLocalScope(
11026 Isolate* isolate,
11027 JavaScriptFrame* frame,
11028 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011029 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011030 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011031 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011032 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011033
11034 // Allocate and initialize a JSObject with all the arguments, stack locals
11035 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011036 Handle<JSObject> local_scope =
11037 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011038
11039 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011040 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011041 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011042 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011043 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011044 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011045 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011046 NONE,
11047 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011048 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011049 }
11050
11051 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011052 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011053 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011054 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011055 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011056 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011057 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011058 NONE,
11059 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011060 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011061 }
11062
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011063 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011064 // Third fill all context locals.
11065 Handle<Context> frame_context(Context::cast(frame->context()));
11066 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011067 if (!CopyContextLocalsToScopeObject(
11068 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011069 return Handle<JSObject>();
11070 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011071
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011072 // Finally copy any properties from the function context extension.
11073 // These will be variables introduced by eval.
11074 if (function_context->closure() == *function) {
11075 if (function_context->has_extension() &&
11076 !function_context->IsGlobalContext()) {
11077 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011078 bool threw = false;
11079 Handle<FixedArray> keys =
11080 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11081 if (threw) return Handle<JSObject>();
11082
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011083 for (int i = 0; i < keys->length(); i++) {
11084 // Names of variables introduced by eval are strings.
11085 ASSERT(keys->get(i)->IsString());
11086 Handle<String> key(String::cast(keys->get(i)));
11087 RETURN_IF_EMPTY_HANDLE_VALUE(
11088 isolate,
11089 SetProperty(local_scope,
11090 key,
11091 GetProperty(ext, key),
11092 NONE,
11093 kNonStrictMode),
11094 Handle<JSObject>());
11095 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011096 }
11097 }
11098 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011099
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100 return local_scope;
11101}
11102
11103
11104// Create a plain JSObject which materializes the closure content for the
11105// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11107 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011108 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011109
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011110 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011111 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112
11113 // Allocate and initialize a JSObject with all the content of theis function
11114 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011115 Handle<JSObject> closure_scope =
11116 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011117
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011118 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011119 if (!CopyContextLocalsToScopeObject(
11120 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011121 return Handle<JSObject>();
11122 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011123
11124 // Finally copy any properties from the function context extension. This will
11125 // be variables introduced by eval.
11126 if (context->has_extension()) {
11127 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011128 bool threw = false;
11129 Handle<FixedArray> keys =
11130 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11131 if (threw) return Handle<JSObject>();
11132
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011133 for (int i = 0; i < keys->length(); i++) {
11134 // Names of variables introduced by eval are strings.
11135 ASSERT(keys->get(i)->IsString());
11136 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011137 RETURN_IF_EMPTY_HANDLE_VALUE(
11138 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011139 SetProperty(closure_scope,
11140 key,
11141 GetProperty(ext, key),
11142 NONE,
11143 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011144 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011145 }
11146 }
11147
11148 return closure_scope;
11149}
11150
11151
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011152// Create a plain JSObject which materializes the scope for the specified
11153// catch context.
11154static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11155 Handle<Context> context) {
11156 ASSERT(context->IsCatchContext());
11157 Handle<String> name(String::cast(context->extension()));
11158 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11159 Handle<JSObject> catch_scope =
11160 isolate->factory()->NewJSObject(isolate->object_function());
11161 RETURN_IF_EMPTY_HANDLE_VALUE(
11162 isolate,
11163 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11164 Handle<JSObject>());
11165 return catch_scope;
11166}
11167
11168
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011169// Create a plain JSObject which materializes the block scope for the specified
11170// block context.
11171static Handle<JSObject> MaterializeBlockScope(
11172 Isolate* isolate,
11173 Handle<Context> context) {
11174 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011175 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011176
11177 // Allocate and initialize a JSObject with all the arguments, stack locals
11178 // heap locals and extension properties of the debugged function.
11179 Handle<JSObject> block_scope =
11180 isolate->factory()->NewJSObject(isolate->object_function());
11181
11182 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011183 if (!CopyContextLocalsToScopeObject(
11184 isolate, scope_info, context, block_scope)) {
11185 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011186 }
11187
11188 return block_scope;
11189}
11190
11191
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011192// Iterate over the actual scopes visible from a stack frame. The iteration
11193// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011194// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011195// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011196class ScopeIterator {
11197 public:
11198 enum ScopeType {
11199 ScopeTypeGlobal = 0,
11200 ScopeTypeLocal,
11201 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011202 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011203 ScopeTypeCatch,
11204 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011205 };
11206
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011207 ScopeIterator(Isolate* isolate,
11208 JavaScriptFrame* frame,
11209 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011210 : isolate_(isolate),
11211 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011212 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011213 function_(JSFunction::cast(frame->function())),
11214 context_(Context::cast(frame->context())),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011215 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011216
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011217 // Catch the case when the debugger stops in an internal function.
11218 Handle<SharedFunctionInfo> shared_info(function_->shared());
11219 if (shared_info->script() == isolate->heap()->undefined_value()) {
11220 while (context_->closure() == *function_) {
11221 context_ = Handle<Context>(context_->previous(), isolate_);
11222 }
11223 return;
11224 }
11225
11226 // Check whether we are in global code or function code. If there is a stack
11227 // slot for .result then this function has been created for evaluating
11228 // global code and it is not a real function.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011229 // Checking for the existence of .result seems fragile, but the scope info
11230 // saved with the code object does not otherwise have that information.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011231 int index = shared_info->scope_info()->
lrn@chromium.org34e60782011-09-15 07:25:40 +000011232 StackSlotIndex(isolate_->heap()->result_symbol());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011233
11234 // Reparse the code and analyze the scopes.
11235 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11236 Handle<Script> script(Script::cast(shared_info->script()));
11237 Scope* scope;
lrn@chromium.org34e60782011-09-15 07:25:40 +000011238 if (index >= 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011239 // Global code
11240 CompilationInfo info(script);
11241 info.MarkAsGlobal();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011242 CHECK(ParserApi::Parse(&info));
11243 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011244 scope = info.function()->scope();
11245 } else {
11246 // Function code
11247 CompilationInfo info(shared_info);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011248 CHECK(ParserApi::Parse(&info));
11249 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011250 scope = info.function()->scope();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011251 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011252
11253 // Retrieve the scope chain for the current position.
11254 int statement_position =
11255 shared_info->code()->SourceStatementPosition(frame_->pc());
11256 scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011257 }
11258
11259 // More scopes?
11260 bool Done() { return context_.is_null(); }
11261
11262 // Move to the next scope.
11263 void Next() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011264 ScopeType scope_type = Type();
11265 if (scope_type == ScopeTypeGlobal) {
11266 // The global scope is always the last in the chain.
11267 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011268 context_ = Handle<Context>();
11269 return;
11270 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011271 if (nested_scope_chain_.is_empty()) {
11272 context_ = Handle<Context>(context_->previous(), isolate_);
11273 } else {
11274 if (nested_scope_chain_.last()->HasContext()) {
11275 context_ = Handle<Context>(context_->previous(), isolate_);
11276 }
11277 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011278 }
11279 }
11280
11281 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011282 ScopeType Type() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011283 if (!nested_scope_chain_.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011284 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011285 switch (scope_info->Type()) {
11286 case FUNCTION_SCOPE:
11287 ASSERT(context_->IsFunctionContext() ||
11288 !scope_info->HasContext());
11289 return ScopeTypeLocal;
11290 case GLOBAL_SCOPE:
11291 ASSERT(context_->IsGlobalContext());
11292 return ScopeTypeGlobal;
11293 case WITH_SCOPE:
11294 ASSERT(context_->IsWithContext());
11295 return ScopeTypeWith;
11296 case CATCH_SCOPE:
11297 ASSERT(context_->IsCatchContext());
11298 return ScopeTypeCatch;
11299 case BLOCK_SCOPE:
11300 ASSERT(!scope_info->HasContext() ||
11301 context_->IsBlockContext());
11302 return ScopeTypeBlock;
11303 case EVAL_SCOPE:
11304 UNREACHABLE();
11305 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011306 }
11307 if (context_->IsGlobalContext()) {
11308 ASSERT(context_->global()->IsGlobalObject());
11309 return ScopeTypeGlobal;
11310 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011311 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011312 return ScopeTypeClosure;
11313 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011314 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011315 return ScopeTypeCatch;
11316 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011317 if (context_->IsBlockContext()) {
11318 return ScopeTypeBlock;
11319 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011320 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011321 return ScopeTypeWith;
11322 }
11323
11324 // Return the JavaScript object with the content of the current scope.
11325 Handle<JSObject> ScopeObject() {
11326 switch (Type()) {
11327 case ScopeIterator::ScopeTypeGlobal:
11328 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011329 case ScopeIterator::ScopeTypeLocal:
11330 // Materialize the content of the local scope into a JSObject.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011331 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011332 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011333 case ScopeIterator::ScopeTypeWith:
11334 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011335 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11336 case ScopeIterator::ScopeTypeCatch:
11337 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011338 case ScopeIterator::ScopeTypeClosure:
11339 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011341 case ScopeIterator::ScopeTypeBlock:
11342 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011343 }
11344 UNREACHABLE();
11345 return Handle<JSObject>();
11346 }
11347
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011348 Handle<ScopeInfo> CurrentScopeInfo() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011349 if (!nested_scope_chain_.is_empty()) {
11350 return nested_scope_chain_.last();
11351 } else if (context_->IsBlockContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011352 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011353 } else if (context_->IsFunctionContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011354 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011355 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011356 return Handle<ScopeInfo>::null();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011357 }
11358
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011359 // Return the context for this scope. For the local context there might not
11360 // be an actual context.
11361 Handle<Context> CurrentContext() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011362 if (Type() == ScopeTypeGlobal ||
11363 nested_scope_chain_.is_empty()) {
11364 return context_;
11365 } else if (nested_scope_chain_.last()->HasContext()) {
11366 return context_;
11367 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368 return Handle<Context>();
11369 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011370 }
11371
11372#ifdef DEBUG
11373 // Debug print of the content of the current scope.
11374 void DebugPrint() {
11375 switch (Type()) {
11376 case ScopeIterator::ScopeTypeGlobal:
11377 PrintF("Global:\n");
11378 CurrentContext()->Print();
11379 break;
11380
11381 case ScopeIterator::ScopeTypeLocal: {
11382 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011383 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011384 if (!CurrentContext().is_null()) {
11385 CurrentContext()->Print();
11386 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011387 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011388 if (extension->IsJSContextExtensionObject()) {
11389 extension->Print();
11390 }
11391 }
11392 }
11393 break;
11394 }
11395
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011396 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011397 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011398 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011399 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011401 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011402 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011403 CurrentContext()->extension()->Print();
11404 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011405 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011406
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011407 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011408 PrintF("Closure:\n");
11409 CurrentContext()->Print();
11410 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011411 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011412 if (extension->IsJSContextExtensionObject()) {
11413 extension->Print();
11414 }
11415 }
11416 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011417
11418 default:
11419 UNREACHABLE();
11420 }
11421 PrintF("\n");
11422 }
11423#endif
11424
11425 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011426 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011427 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011428 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011429 Handle<JSFunction> function_;
11430 Handle<Context> context_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011431 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011432
11433 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11434};
11435
11436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011437RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011439 ASSERT(args.length() == 2);
11440
11441 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011442 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011443 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11444 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011445 if (!maybe_check->ToObject(&check)) return maybe_check;
11446 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011447 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11448
11449 // Get the frame where the debugging is performed.
11450 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011451 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011452 JavaScriptFrame* frame = it.frame();
11453
11454 // Count the visible scopes.
11455 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011456 for (ScopeIterator it(isolate, frame, 0);
11457 !it.Done();
11458 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011459 n++;
11460 }
11461
11462 return Smi::FromInt(n);
11463}
11464
11465
11466static const int kScopeDetailsTypeIndex = 0;
11467static const int kScopeDetailsObjectIndex = 1;
11468static const int kScopeDetailsSize = 2;
11469
11470// Return an array with scope details
11471// args[0]: number: break id
11472// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011473// args[2]: number: inlined frame index
11474// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011475//
11476// The array returned contains the following information:
11477// 0: Scope type
11478// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011479RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011480 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011481 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011482
11483 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011484 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011485 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11486 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011487 if (!maybe_check->ToObject(&check)) return maybe_check;
11488 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011489 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011490 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11491 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011492
11493 // Get the frame where the debugging is performed.
11494 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011495 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011496 JavaScriptFrame* frame = frame_it.frame();
11497
11498 // Find the requested scope.
11499 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011500 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501 for (; !it.Done() && n < index; it.Next()) {
11502 n++;
11503 }
11504 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011505 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011506 }
11507
11508 // Calculate the size of the result.
11509 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011510 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011511
11512 // Fill in scope details.
11513 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011514 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011516 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011518 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011519}
11520
11521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011522RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011523 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011524 ASSERT(args.length() == 0);
11525
11526#ifdef DEBUG
11527 // Print the scopes for the top frame.
11528 StackFrameLocator locator;
11529 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011530 for (ScopeIterator it(isolate, frame, 0);
11531 !it.Done();
11532 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011533 it.DebugPrint();
11534 }
11535#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011536 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011537}
11538
11539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011540RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011542 ASSERT(args.length() == 1);
11543
11544 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011545 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011546 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11547 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011548 if (!maybe_result->ToObject(&result)) return maybe_result;
11549 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011550
11551 // Count all archived V8 threads.
11552 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 for (ThreadState* thread =
11554 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011555 thread != NULL;
11556 thread = thread->Next()) {
11557 n++;
11558 }
11559
11560 // Total number of threads is current thread and archived threads.
11561 return Smi::FromInt(n + 1);
11562}
11563
11564
11565static const int kThreadDetailsCurrentThreadIndex = 0;
11566static const int kThreadDetailsThreadIdIndex = 1;
11567static const int kThreadDetailsSize = 2;
11568
11569// Return an array with thread details
11570// args[0]: number: break id
11571// args[1]: number: thread index
11572//
11573// The array returned contains the following information:
11574// 0: Is current thread?
11575// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011576RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011577 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011578 ASSERT(args.length() == 2);
11579
11580 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011581 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011582 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11583 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011584 if (!maybe_check->ToObject(&check)) return maybe_check;
11585 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011586 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11587
11588 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011589 Handle<FixedArray> details =
11590 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011591
11592 // Thread index 0 is current thread.
11593 if (index == 0) {
11594 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 details->set(kThreadDetailsCurrentThreadIndex,
11596 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011597 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011598 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011599 } else {
11600 // Find the thread with the requested index.
11601 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 ThreadState* thread =
11603 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011604 while (index != n && thread != NULL) {
11605 thread = thread->Next();
11606 n++;
11607 }
11608 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011610 }
11611
11612 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011613 details->set(kThreadDetailsCurrentThreadIndex,
11614 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011615 details->set(kThreadDetailsThreadIdIndex,
11616 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011617 }
11618
11619 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011621}
11622
11623
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011624// Sets the disable break state
11625// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011626RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011628 ASSERT(args.length() == 1);
11629 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 isolate->debug()->set_disable_break(disable_break);
11631 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011632}
11633
11634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011635RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637 ASSERT(args.length() == 1);
11638
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011639 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11640 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011641 // Find the number of break points
11642 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011643 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011644 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011646 Handle<FixedArray>::cast(break_locations));
11647}
11648
11649
11650// Set a break point in a function
11651// args[0]: function
11652// args[1]: number: break source position (within the function source)
11653// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011654RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011656 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011657 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11658 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011659 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11660 RUNTIME_ASSERT(source_position >= 0);
11661 Handle<Object> break_point_object_arg = args.at<Object>(2);
11662
11663 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11665 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011666
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011667 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011668}
11669
11670
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11672 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011673 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011674 // Iterate the heap looking for SharedFunctionInfo generated from the
11675 // script. The inner most SharedFunctionInfo containing the source position
11676 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011677 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011678 // which is found is not compiled it is compiled and the heap is iterated
11679 // again as the compilation might create inner functions from the newly
11680 // compiled function and the actual requested break point might be in one of
11681 // these functions.
11682 bool done = false;
11683 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011684 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011685 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011686 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011687 { // Extra scope for iterator and no-allocation.
11688 isolate->heap()->EnsureHeapIsIterable();
11689 AssertNoAllocation no_alloc_during_heap_iteration;
11690 HeapIterator iterator;
11691 for (HeapObject* obj = iterator.next();
11692 obj != NULL; obj = iterator.next()) {
11693 if (obj->IsSharedFunctionInfo()) {
11694 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11695 if (shared->script() == *script) {
11696 // If the SharedFunctionInfo found has the requested script data and
11697 // contains the source position it is a candidate.
11698 int start_position = shared->function_token_position();
11699 if (start_position == RelocInfo::kNoPosition) {
11700 start_position = shared->start_position();
11701 }
11702 if (start_position <= position &&
11703 position <= shared->end_position()) {
11704 // If there is no candidate or this function is within the current
11705 // candidate this is the new candidate.
11706 if (target.is_null()) {
11707 target_start_position = start_position;
11708 target = shared;
11709 } else {
11710 if (target_start_position == start_position &&
11711 shared->end_position() == target->end_position()) {
11712 // If a top-level function contain only one function
11713 // declartion the source for the top-level and the
11714 // function is the same. In that case prefer the non
11715 // top-level function.
11716 if (!shared->is_toplevel()) {
11717 target_start_position = start_position;
11718 target = shared;
11719 }
11720 } else if (target_start_position <= start_position &&
11721 shared->end_position() <= target->end_position()) {
11722 // This containment check includes equality as a function
11723 // inside a top-level function can share either start or end
11724 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011725 target_start_position = start_position;
11726 target = shared;
11727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011728 }
11729 }
11730 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011731 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011732 } // End for loop.
11733 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011735 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011736 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011737 }
11738
11739 // If the candidate found is compiled we are done. NOTE: when lazy
11740 // compilation of inner functions is introduced some additional checking
11741 // needs to be done here to compile inner functions.
11742 done = target->is_compiled();
11743 if (!done) {
11744 // If the candidate is not compiled compile it to reveal any inner
11745 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011746 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011747 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011748 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011749
11750 return *target;
11751}
11752
11753
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011754// Changes the state of a break point in a script and returns source position
11755// where break point was set. NOTE: Regarding performance see the NOTE for
11756// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757// args[0]: script to set break point in
11758// args[1]: number: break source position (within the script source)
11759// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011760RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 ASSERT(args.length() == 3);
11763 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11764 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11765 RUNTIME_ASSERT(source_position >= 0);
11766 Handle<Object> break_point_object_arg = args.at<Object>(2);
11767
11768 // Get the script from the script wrapper.
11769 RUNTIME_ASSERT(wrapper->value()->IsScript());
11770 Handle<Script> script(Script::cast(wrapper->value()));
11771
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011772 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 if (!result->IsUndefined()) {
11775 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11776 // Find position within function. The script position might be before the
11777 // source position of the first function.
11778 int position;
11779 if (shared->start_position() > source_position) {
11780 position = 0;
11781 } else {
11782 position = source_position - shared->start_position();
11783 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011785 position += shared->start_position();
11786 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011788 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789}
11790
11791
11792// Clear a break point
11793// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011794RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011796 ASSERT(args.length() == 1);
11797 Handle<Object> break_point_object_arg = args.at<Object>(0);
11798
11799 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011800 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011802 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011803}
11804
11805
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011806// Change the state of break on exceptions.
11807// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11808// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011809RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011812 RUNTIME_ASSERT(args[0]->IsNumber());
11813 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011814
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011815 // If the number doesn't match an enum value, the ChangeBreakOnException
11816 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 ExceptionBreakType type =
11818 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011819 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011820 isolate->debug()->ChangeBreakOnException(type, enable);
11821 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011822}
11823
11824
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011825// Returns the state of break on exceptions
11826// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011827RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011828 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011829 ASSERT(args.length() == 1);
11830 RUNTIME_ASSERT(args[0]->IsNumber());
11831
11832 ExceptionBreakType type =
11833 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011834 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011835 return Smi::FromInt(result);
11836}
11837
11838
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839// Prepare for stepping
11840// args[0]: break id for checking execution state
11841// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011842// args[2]: number of times to perform the step, for step out it is the number
11843// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011844RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011845 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 ASSERT(args.length() == 3);
11847 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011848 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011849 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11850 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011851 if (!maybe_check->ToObject(&check)) return maybe_check;
11852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011854 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011855 }
11856
11857 // Get the step action and check validity.
11858 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11859 if (step_action != StepIn &&
11860 step_action != StepNext &&
11861 step_action != StepOut &&
11862 step_action != StepInMin &&
11863 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865 }
11866
11867 // Get the number of steps.
11868 int step_count = NumberToInt32(args[2]);
11869 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011870 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871 }
11872
ager@chromium.orga1645e22009-09-09 19:27:10 +000011873 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011875
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011876 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11878 step_count);
11879 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880}
11881
11882
11883// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011884RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011885 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011886 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011887 isolate->debug()->ClearStepping();
11888 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889}
11890
11891
11892// Creates a copy of the with context chain. The copy of the context chain is
11893// is linked to the function context supplied.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011894static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11895 Handle<JSFunction> function,
11896 Handle<Context> base,
11897 JavaScriptFrame* frame,
11898 int inlined_frame_index) {
11899 HandleScope scope(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011900 List<Handle<ScopeInfo> > scope_chain;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011901 List<Handle<Context> > context_chain;
11902
11903 ScopeIterator it(isolate, frame, inlined_frame_index);
11904 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11905 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11906 ASSERT(!it.Done());
11907 scope_chain.Add(it.CurrentScopeInfo());
11908 context_chain.Add(it.CurrentContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011909 }
11910
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011911 // At the end of the chain. Return the base context to link to.
11912 Handle<Context> context = base;
11913
11914 // Iteratively copy and or materialize the nested contexts.
11915 while (!scope_chain.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011916 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011917 Handle<Context> current = context_chain.RemoveLast();
11918 ASSERT(!(scope_info->HasContext() & current.is_null()));
11919
11920 if (scope_info->Type() == CATCH_SCOPE) {
11921 Handle<String> name(String::cast(current->extension()));
11922 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11923 context =
11924 isolate->factory()->NewCatchContext(function,
11925 context,
11926 name,
11927 thrown_object);
11928 } else if (scope_info->Type() == BLOCK_SCOPE) {
11929 // Materialize the contents of the block scope into a JSObject.
11930 Handle<JSObject> block_scope_object =
11931 MaterializeBlockScope(isolate, current);
11932 if (block_scope_object.is_null()) {
11933 return Handle<Context>::null();
11934 }
11935 // Allocate a new function context for the debug evaluation and set the
11936 // extension object.
11937 Handle<Context> new_context =
11938 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11939 function);
11940 new_context->set_extension(*block_scope_object);
11941 new_context->set_previous(*context);
11942 context = new_context;
11943 } else {
11944 ASSERT(scope_info->Type() == WITH_SCOPE);
11945 ASSERT(current->IsWithContext());
11946 Handle<JSObject> extension(JSObject::cast(current->extension()));
11947 context =
11948 isolate->factory()->NewWithContext(function, context, extension);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011949 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011950 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011951
11952 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011953}
11954
11955
11956// Helper function to find or create the arguments object for
11957// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011958static Handle<Object> GetArgumentsObject(Isolate* isolate,
11959 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011960 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011962 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963 Handle<Context> function_context) {
11964 // Try to find the value of 'arguments' to pass as parameter. If it is not
11965 // found (that is the debugged function does not reference 'arguments' and
11966 // does not support eval) then create an 'arguments' object.
11967 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011968 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011969 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011971 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011972 }
11973 }
11974
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011975 if (scope_info->HasHeapAllocatedLocals()) {
11976 VariableMode mode;
11977 InitializationFlag init_flag;
11978 index = scope_info->ContextSlotIndex(
11979 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011981 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011982 }
11983 }
11984
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011985 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11986
11987 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011988 Handle<JSObject> arguments =
11989 isolate->factory()->NewArgumentsObject(function, length);
11990 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011991
11992 AssertNoAllocation no_gc;
11993 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011994 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011995 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011997 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 return arguments;
11999}
12000
12001
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002static const char kSourceStr[] =
12003 "(function(arguments,__source__){return eval(__source__);})";
12004
12005
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012006// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012007// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012008// extension part has all the parameters and locals of the function on the
12009// stack frame. A function which calls eval with the code to evaluate is then
12010// compiled in this context and called in this context. As this context
12011// replaces the context of the function on the stack frame a new (empty)
12012// function is created as well to be used as the closure for the context.
12013// This function and the context acts as replacements for the function on the
12014// stack frame presenting the same view of the values of parameters and
12015// local variables as if the piece of JavaScript was evaluated at the point
12016// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012017RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012019
12020 // Check the execution state and decode arguments frame and source to be
12021 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012022 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012023 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012024 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12025 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012026 if (!maybe_check_result->ToObject(&check_result)) {
12027 return maybe_check_result;
12028 }
12029 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012030 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012031 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12032 CONVERT_ARG_CHECKED(String, source, 3);
12033 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12034 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012035
12036 // Handle the processing of break.
12037 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012038
12039 // Get the frame where the debugging is performed.
12040 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012041 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012042 JavaScriptFrame* frame = it.frame();
12043 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012044 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012045
12046 // Traverse the saved contexts chain to find the active context for the
12047 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012048 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12049
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012050 SaveContext savex(isolate);
12051 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012052
12053 // Create the (empty) function replacing the function on the stack frame for
12054 // the purpose of evaluating in the context created below. It is important
12055 // that this function does not describe any parameters and local variables
12056 // in the context. If it does then this will cause problems with the lookup
12057 // in Context::Lookup, where context slots for parameters and local variables
12058 // are looked at before the extension object.
12059 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012060 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12061 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012062 go_between->set_context(function->context());
12063#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012064 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12065 ASSERT(go_between_scope_info->ParameterCount() == 0);
12066 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012067#endif
12068
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012069 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012070 Handle<JSObject> local_scope = MaterializeLocalScope(
12071 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012072 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012073
12074 // Allocate a new context for the debug evaluation and set the extension
12075 // object build.
12076 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12078 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012079 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012080 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012081 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012082 Handle<Context> function_context;
12083 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012084 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012085 function_context = Handle<Context>(frame_context->declaration_context());
12086 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012087 context = CopyNestedScopeContextChain(isolate,
12088 go_between,
12089 context,
12090 frame,
12091 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012092
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012093 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012094 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012095 context =
12096 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012097 }
12098
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 // Wrap the evaluation statement in a new function compiled in the newly
12100 // created context. The function has one parameter which has to be called
12101 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012102 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012103 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012105 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012106 isolate->factory()->NewStringFromAscii(
12107 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012108
12109 // Currently, the eval code will be executed in non-strict mode,
12110 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012111 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012112 Compiler::CompileEval(function_source,
12113 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012114 context->IsGlobalContext(),
12115 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012116 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012118 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119
12120 // Invoke the result of the compilation to get the evaluation function.
12121 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012122 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123 Handle<Object> evaluation_function =
12124 Execution::Call(compiled_function, receiver, 0, NULL,
12125 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012126 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012128 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012129 frame,
12130 inlined_frame_index,
12131 function,
12132 scope_info,
12133 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134
12135 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012136 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012137 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012138 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12139 receiver,
12140 ARRAY_SIZE(argv),
12141 argv,
12142 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012143 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012144
12145 // Skip the global proxy as it has no properties and always delegates to the
12146 // real global object.
12147 if (result->IsJSGlobalProxy()) {
12148 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12149 }
12150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151 return *result;
12152}
12153
12154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012155RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157
12158 // Check the execution state and decode arguments frame and source to be
12159 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012160 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012161 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012162 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12163 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012164 if (!maybe_check_result->ToObject(&check_result)) {
12165 return maybe_check_result;
12166 }
12167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012168 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012169 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012170 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012171
12172 // Handle the processing of break.
12173 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174
12175 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012176 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012178 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012179 top = top->prev();
12180 }
12181 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012182 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012183 }
12184
12185 // Get the global context now set to the top context from before the
12186 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012189 bool is_global = true;
12190
12191 if (additional_context->IsJSObject()) {
12192 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012193 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
12194 isolate->factory()->empty_string(),
12195 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012196 go_between->set_context(*context);
12197 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012198 isolate->factory()->NewFunctionContext(
12199 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012200 context->set_extension(JSObject::cast(*additional_context));
12201 is_global = false;
12202 }
12203
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012205 // Currently, the eval code will be executed in non-strict mode,
12206 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012207 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012208 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012209 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012211 Handle<JSFunction>(
12212 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12213 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012214
12215 // Invoke the result of the compilation to get the evaluation function.
12216 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012217 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012218 Handle<Object> result =
12219 Execution::Call(compiled_function, receiver, 0, NULL,
12220 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012221 // Clear the oneshot breakpoints so that the debugger does not step further.
12222 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012223 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224 return *result;
12225}
12226
12227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012228RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012229 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012230 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012233 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012234
12235 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012236 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012237 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12238 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12239 // because using
12240 // instances->set(i, *GetScriptWrapper(script))
12241 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12242 // already have deferenced the instances handle.
12243 Handle<JSValue> wrapper = GetScriptWrapper(script);
12244 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012245 }
12246
12247 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012248 Handle<JSObject> result =
12249 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012250 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 return *result;
12252}
12253
12254
12255// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012256static int DebugReferencedBy(HeapIterator* iterator,
12257 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258 Object* instance_filter, int max_references,
12259 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012260 JSFunction* arguments_function) {
12261 NoHandleAllocation ha;
12262 AssertNoAllocation no_alloc;
12263
12264 // Iterate the heap.
12265 int count = 0;
12266 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012267 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012268 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 (max_references == 0 || count < max_references)) {
12270 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012271 if (heap_obj->IsJSObject()) {
12272 // Skip context extension objects and argument arrays as these are
12273 // checked in the context of functions using them.
12274 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012275 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012276 obj->map()->constructor() == arguments_function) {
12277 continue;
12278 }
12279
12280 // Check if the JS object has a reference to the object looked for.
12281 if (obj->ReferencesObject(target)) {
12282 // Check instance filter if supplied. This is normally used to avoid
12283 // references from mirror objects (see Runtime_IsInPrototypeChain).
12284 if (!instance_filter->IsUndefined()) {
12285 Object* V = obj;
12286 while (true) {
12287 Object* prototype = V->GetPrototype();
12288 if (prototype->IsNull()) {
12289 break;
12290 }
12291 if (instance_filter == prototype) {
12292 obj = NULL; // Don't add this object.
12293 break;
12294 }
12295 V = prototype;
12296 }
12297 }
12298
12299 if (obj != NULL) {
12300 // Valid reference found add to instance array if supplied an update
12301 // count.
12302 if (instances != NULL && count < instances_size) {
12303 instances->set(count, obj);
12304 }
12305 last = obj;
12306 count++;
12307 }
12308 }
12309 }
12310 }
12311
12312 // Check for circular reference only. This can happen when the object is only
12313 // referenced from mirrors and has a circular reference in which case the
12314 // object is not really alive and would have been garbage collected if not
12315 // referenced from the mirror.
12316 if (count == 1 && last == target) {
12317 count = 0;
12318 }
12319
12320 // Return the number of referencing objects found.
12321 return count;
12322}
12323
12324
12325// Scan the heap for objects with direct references to an object
12326// args[0]: the object to find references to
12327// args[1]: constructor function for instances to exclude (Mirror)
12328// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012329RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330 ASSERT(args.length() == 3);
12331
12332 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012333 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12334 // The heap iterator reserves the right to do a GC to make the heap iterable.
12335 // Due to the GC above we know it won't need to do that, but it seems cleaner
12336 // to get the heap iterator constructed before we start having unprotected
12337 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012338
12339 // Check parameters.
12340 CONVERT_CHECKED(JSObject, target, args[0]);
12341 Object* instance_filter = args[1];
12342 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12343 instance_filter->IsJSObject());
12344 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12345 RUNTIME_ASSERT(max_references >= 0);
12346
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012348 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012349 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012350 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012351 JSFunction* arguments_function =
12352 JSFunction::cast(arguments_boilerplate->map()->constructor());
12353
12354 // Get the number of referencing objects.
12355 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012356 HeapIterator heap_iterator;
12357 count = DebugReferencedBy(&heap_iterator,
12358 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012359 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012360
12361 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012362 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012363 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012364 if (!maybe_object->ToObject(&object)) return maybe_object;
12365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012366 FixedArray* instances = FixedArray::cast(object);
12367
12368 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012369 // AllocateFixedArray above does not make the heap non-iterable.
12370 ASSERT(HEAP->IsHeapIterable());
12371 HeapIterator heap_iterator2;
12372 count = DebugReferencedBy(&heap_iterator2,
12373 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012374 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012375
12376 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012377 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012378 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012380 if (!maybe_result->ToObject(&result)) return maybe_result;
12381 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012382}
12383
12384
12385// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012386static int DebugConstructedBy(HeapIterator* iterator,
12387 JSFunction* constructor,
12388 int max_references,
12389 FixedArray* instances,
12390 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012391 AssertNoAllocation no_alloc;
12392
12393 // Iterate the heap.
12394 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012395 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012396 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012397 (max_references == 0 || count < max_references)) {
12398 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012399 if (heap_obj->IsJSObject()) {
12400 JSObject* obj = JSObject::cast(heap_obj);
12401 if (obj->map()->constructor() == constructor) {
12402 // Valid reference found add to instance array if supplied an update
12403 // count.
12404 if (instances != NULL && count < instances_size) {
12405 instances->set(count, obj);
12406 }
12407 count++;
12408 }
12409 }
12410 }
12411
12412 // Return the number of referencing objects found.
12413 return count;
12414}
12415
12416
12417// Scan the heap for objects constructed by a specific function.
12418// args[0]: the constructor to find instances of
12419// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012420RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012421 ASSERT(args.length() == 2);
12422
12423 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012424 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012425
12426 // Check parameters.
12427 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12428 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12429 RUNTIME_ASSERT(max_references >= 0);
12430
12431 // Get the number of referencing objects.
12432 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012433 HeapIterator heap_iterator;
12434 count = DebugConstructedBy(&heap_iterator,
12435 constructor,
12436 max_references,
12437 NULL,
12438 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012439
12440 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012441 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012442 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012443 if (!maybe_object->ToObject(&object)) return maybe_object;
12444 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012445 FixedArray* instances = FixedArray::cast(object);
12446
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012447 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012448 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012449 HeapIterator heap_iterator2;
12450 count = DebugConstructedBy(&heap_iterator2,
12451 constructor,
12452 max_references,
12453 instances,
12454 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012455
12456 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012457 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012458 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12459 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012460 if (!maybe_result->ToObject(&result)) return maybe_result;
12461 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012462 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012463}
12464
12465
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012466// Find the effective prototype object as returned by __proto__.
12467// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012468RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012469 ASSERT(args.length() == 1);
12470
12471 CONVERT_CHECKED(JSObject, obj, args[0]);
12472
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012473 // Use the __proto__ accessor.
12474 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012475}
12476
12477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012478RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012479 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012480 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012481 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482}
12483
12484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012485RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012486#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012487 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012488 ASSERT(args.length() == 1);
12489 // Get the function and make sure it is compiled.
12490 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012491 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012492 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012493 return Failure::Exception();
12494 }
12495 func->code()->PrintLn();
12496#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012497 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012498}
ager@chromium.org9085a012009-05-11 19:22:57 +000012499
12500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012501RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012502#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012503 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012504 ASSERT(args.length() == 1);
12505 // Get the function and make sure it is compiled.
12506 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012507 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012508 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012509 return Failure::Exception();
12510 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012511 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012512#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012513 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012514}
12515
12516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012517RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012518 NoHandleAllocation ha;
12519 ASSERT(args.length() == 1);
12520
12521 CONVERT_CHECKED(JSFunction, f, args[0]);
12522 return f->shared()->inferred_name();
12523}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012525
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012526static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12527 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012528 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012529 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012530 int counter = 0;
12531 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012532 for (HeapObject* obj = iterator->next();
12533 obj != NULL;
12534 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012535 ASSERT(obj != NULL);
12536 if (!obj->IsSharedFunctionInfo()) {
12537 continue;
12538 }
12539 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12540 if (shared->script() != script) {
12541 continue;
12542 }
12543 if (counter < buffer_size) {
12544 buffer->set(counter, shared);
12545 }
12546 counter++;
12547 }
12548 return counter;
12549}
12550
12551// For a script finds all SharedFunctionInfo's in the heap that points
12552// to this script. Returns JSArray of SharedFunctionInfo wrapped
12553// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012554RUNTIME_FUNCTION(MaybeObject*,
12555 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012556 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012557 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012558 CONVERT_CHECKED(JSValue, script_value, args[0]);
12559
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012560
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012561 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12562
12563 const int kBufferSize = 32;
12564
12565 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012566 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012567 int number;
12568 {
12569 isolate->heap()->EnsureHeapIsIterable();
12570 AssertNoAllocation no_allocations;
12571 HeapIterator heap_iterator;
12572 Script* scr = *script;
12573 FixedArray* arr = *array;
12574 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12575 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012576 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012577 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012578 isolate->heap()->EnsureHeapIsIterable();
12579 AssertNoAllocation no_allocations;
12580 HeapIterator heap_iterator;
12581 Script* scr = *script;
12582 FixedArray* arr = *array;
12583 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012584 }
12585
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012586 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012587 result->set_length(Smi::FromInt(number));
12588
12589 LiveEdit::WrapSharedFunctionInfos(result);
12590
12591 return *result;
12592}
12593
12594// For a script calculates compilation information about all its functions.
12595// The script source is explicitly specified by the second argument.
12596// The source of the actual script is not used, however it is important that
12597// all generated code keeps references to this particular instance of script.
12598// Returns a JSArray of compilation infos. The array is ordered so that
12599// each function with all its descendant is always stored in a continues range
12600// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012601RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012602 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012604 CONVERT_CHECKED(JSValue, script, args[0]);
12605 CONVERT_ARG_CHECKED(String, source, 1);
12606 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12607
12608 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012610 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012611 return Failure::Exception();
12612 }
12613
12614 return result;
12615}
12616
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012617// Changes the source of the script to a new_source.
12618// If old_script_name is provided (i.e. is a String), also creates a copy of
12619// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012620RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012621 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012622 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012623 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12624 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012625 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012626
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012627 CONVERT_CHECKED(Script, original_script_pointer,
12628 original_script_value->value());
12629 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012630
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012631 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12632 new_source,
12633 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012634
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012635 if (old_script->IsScript()) {
12636 Handle<Script> script_handle(Script::cast(old_script));
12637 return *(GetScriptWrapper(script_handle));
12638 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012639 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012640 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012641}
12642
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012644RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012645 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012646 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012647 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12648 return LiveEdit::FunctionSourceUpdated(shared_info);
12649}
12650
12651
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012652// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012653RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012654 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012655 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012656 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12657 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12658
ager@chromium.orgac091b72010-05-05 07:34:42 +000012659 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012660}
12661
12662// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012663RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012664 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012665 HandleScope scope(isolate);
12666 Handle<Object> function_object(args[0], isolate);
12667 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012668
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012669 if (function_object->IsJSValue()) {
12670 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12671 if (script_object->IsJSValue()) {
12672 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012673 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012674 }
12675
12676 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12677 } else {
12678 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12679 // and we check it in this function.
12680 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012681
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012682 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012683}
12684
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012685
12686// In a code of a parent function replaces original function as embedded object
12687// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012688RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012689 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012690 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012691
12692 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12693 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12694 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12695
12696 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12697 subst_wrapper);
12698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012699 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012700}
12701
12702
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012703// Updates positions of a shared function info (first parameter) according
12704// to script source change. Text change is described in second parameter as
12705// array of groups of 3 numbers:
12706// (change_begin, change_end, change_end_new_position).
12707// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012708RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012709 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012710 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012711 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12712 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12713
ager@chromium.orgac091b72010-05-05 07:34:42 +000012714 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012715}
12716
12717
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012718// For array of SharedFunctionInfo's (each wrapped in JSValue)
12719// checks that none of them have activations on stacks (of any thread).
12720// Returns array of the same length with corresponding results of
12721// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012722RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012723 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012724 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012725 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012726 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012727
ager@chromium.org357bf652010-04-12 11:30:10 +000012728 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012729}
12730
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012731// Compares 2 strings line-by-line, then token-wise and returns diff in form
12732// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12733// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012734RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012735 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012736 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012737 CONVERT_ARG_CHECKED(String, s1, 0);
12738 CONVERT_ARG_CHECKED(String, s2, 1);
12739
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012740 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012741}
12742
12743
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012744// A testing entry. Returns statement position which is the closest to
12745// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012746RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012747 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012748 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012749 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12750 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012752 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012753
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012754 if (code->kind() != Code::FUNCTION &&
12755 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012757 }
12758
12759 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012760 int closest_pc = 0;
12761 int distance = kMaxInt;
12762 while (!it.done()) {
12763 int statement_position = static_cast<int>(it.rinfo()->data());
12764 // Check if this break point is closer that what was previously found.
12765 if (source_position <= statement_position &&
12766 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012767 closest_pc =
12768 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012769 distance = statement_position - source_position;
12770 // Check whether we can't get any closer.
12771 if (distance == 0) break;
12772 }
12773 it.next();
12774 }
12775
12776 return Smi::FromInt(closest_pc);
12777}
12778
12779
ager@chromium.org357bf652010-04-12 11:30:10 +000012780// Calls specified function with or without entering the debugger.
12781// This is used in unit tests to run code as if debugger is entered or simply
12782// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012783RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012784 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012785 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012786 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12787 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12788
12789 Handle<Object> result;
12790 bool pending_exception;
12791 {
12792 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012793 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012794 &pending_exception);
12795 } else {
12796 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012797 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012798 &pending_exception);
12799 }
12800 }
12801 if (!pending_exception) {
12802 return *result;
12803 } else {
12804 return Failure::Exception();
12805 }
12806}
12807
12808
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012809// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012810RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012811 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012812 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012813 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12814 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012816}
12817
12818
12819// Performs a GC.
12820// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012821RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012822 isolate->heap()->CollectAllGarbage(true);
12823 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012824}
12825
12826
12827// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012828RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012829 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012830 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012831 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012832 }
12833 return Smi::FromInt(usage);
12834}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012835
12836
12837// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012838RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012839#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012840 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012841#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012843#endif
12844}
12845
12846
12847// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012848RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012849#ifdef LIVE_OBJECT_LIST
12850 return LiveObjectList::Capture();
12851#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012852 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012853#endif
12854}
12855
12856
12857// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012858RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012859#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012860 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012861 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012862 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012863#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012864 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012865#endif
12866}
12867
12868
12869// Generates the response to a debugger request for a dump of the objects
12870// contained in the difference between the captured live object lists
12871// specified by id1 and id2.
12872// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12873// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012874RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012875#ifdef LIVE_OBJECT_LIST
12876 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012877 CONVERT_SMI_ARG_CHECKED(id1, 0);
12878 CONVERT_SMI_ARG_CHECKED(id2, 1);
12879 CONVERT_SMI_ARG_CHECKED(start, 2);
12880 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012881 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12882 EnterDebugger enter_debugger;
12883 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12884#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012885 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012886#endif
12887}
12888
12889
12890// Gets the specified object as requested by the debugger.
12891// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012892RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012893#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012894 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012895 Object* result = LiveObjectList::GetObj(obj_id);
12896 return result;
12897#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012898 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012899#endif
12900}
12901
12902
12903// Gets the obj id for the specified address if valid.
12904// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012905RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012906#ifdef LIVE_OBJECT_LIST
12907 HandleScope scope;
12908 CONVERT_ARG_CHECKED(String, address, 0);
12909 Object* result = LiveObjectList::GetObjId(address);
12910 return result;
12911#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012912 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012913#endif
12914}
12915
12916
12917// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012918RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012919#ifdef LIVE_OBJECT_LIST
12920 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012921 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012922 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12923 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12924 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12925 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12926 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12927
12928 Handle<JSObject> instance_filter;
12929 if (args[1]->IsJSObject()) {
12930 instance_filter = args.at<JSObject>(1);
12931 }
12932 bool verbose = false;
12933 if (args[2]->IsBoolean()) {
12934 verbose = args[2]->IsTrue();
12935 }
12936 int start = 0;
12937 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012938 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012939 }
12940 int limit = Smi::kMaxValue;
12941 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012942 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012943 }
12944
12945 return LiveObjectList::GetObjRetainers(obj_id,
12946 instance_filter,
12947 verbose,
12948 start,
12949 limit,
12950 filter_obj);
12951#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012952 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012953#endif
12954}
12955
12956
12957// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012958RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012959#ifdef LIVE_OBJECT_LIST
12960 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012961 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12962 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012963 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12964
12965 Handle<JSObject> instance_filter;
12966 if (args[2]->IsJSObject()) {
12967 instance_filter = args.at<JSObject>(2);
12968 }
12969
12970 Object* result =
12971 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12972 return result;
12973#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012974 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012975#endif
12976}
12977
12978
12979// Generates the response to a debugger request for a list of all
12980// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012981RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012982#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012983 CONVERT_SMI_ARG_CHECKED(start, 0);
12984 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012985 return LiveObjectList::Info(start, count);
12986#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012987 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012988#endif
12989}
12990
12991
12992// Gets a dump of the specified object as requested by the debugger.
12993// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012994RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012995#ifdef LIVE_OBJECT_LIST
12996 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012997 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012998 Object* result = LiveObjectList::PrintObj(obj_id);
12999 return result;
13000#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013001 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013002#endif
13003}
13004
13005
13006// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013007RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013008#ifdef LIVE_OBJECT_LIST
13009 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013010 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013011#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013012 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013013#endif
13014}
13015
13016
13017// Generates the response to a debugger request for a summary of the types
13018// of objects in the difference between the captured live object lists
13019// specified by id1 and id2.
13020// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13021// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013022RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013023#ifdef LIVE_OBJECT_LIST
13024 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013025 CONVERT_SMI_ARG_CHECKED(id1, 0);
13026 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013027 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13028
13029 EnterDebugger enter_debugger;
13030 return LiveObjectList::Summarize(id1, id2, filter_obj);
13031#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013032 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013033#endif
13034}
13035
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013036#endif // ENABLE_DEBUGGER_SUPPORT
13037
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013039RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013040 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013041 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013042 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013043}
13044
13045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013046RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013047 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013048 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013049 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013050}
13051
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013053// Finds the script object from the script data. NOTE: This operation uses
13054// heap traversal to find the function generated for the source position
13055// for the requested break point. For lazily compiled functions several heap
13056// traversals might be required rendering this operation as a rather slow
13057// operation. However for setting break points which is normally done through
13058// some kind of user interaction the performance is not crucial.
13059static Handle<Object> Runtime_GetScriptFromScriptName(
13060 Handle<String> script_name) {
13061 // Scan the heap for Script objects to find the script with the requested
13062 // script data.
13063 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013064 script_name->GetHeap()->EnsureHeapIsIterable();
13065 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013066 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013067 HeapObject* obj = NULL;
13068 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013069 // If a script is found check if it has the script data requested.
13070 if (obj->IsScript()) {
13071 if (Script::cast(obj)->name()->IsString()) {
13072 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13073 script = Handle<Script>(Script::cast(obj));
13074 }
13075 }
13076 }
13077 }
13078
13079 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013080 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013081
13082 // Return the script found.
13083 return GetScriptWrapper(script);
13084}
13085
13086
13087// Get the script object from script data. NOTE: Regarding performance
13088// see the NOTE for GetScriptFromScriptData.
13089// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013090RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013091 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013092
13093 ASSERT(args.length() == 1);
13094
13095 CONVERT_CHECKED(String, script_name, args[0]);
13096
13097 // Find the requested script.
13098 Handle<Object> result =
13099 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13100 return *result;
13101}
13102
13103
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013104// Determines whether the given stack frame should be displayed in
13105// a stack trace. The caller is the error constructor that asked
13106// for the stack trace to be collected. The first time a construct
13107// call to this function is encountered it is skipped. The seen_caller
13108// in/out parameter is used to remember if the caller has been seen
13109// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013110static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13111 Object* caller,
13112 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013113 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013114 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013115 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013116 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013117 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13118 Object* raw_fun = frame->function();
13119 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013120 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013121 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013122 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013123 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013124 *seen_caller = true;
13125 return false;
13126 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013127 // Skip all frames until we've seen the caller.
13128 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013129 // Also, skip non-visible built-in functions and any call with the builtins
13130 // object as receiver, so as to not reveal either the builtins object or
13131 // an internal function.
13132 // The --builtins-in-stack-traces command line flag allows including
13133 // internal call sites in the stack trace for debugging purposes.
13134 if (!FLAG_builtins_in_stack_traces) {
13135 JSFunction* fun = JSFunction::cast(raw_fun);
13136 if (frame->receiver()->IsJSBuiltinsObject() ||
13137 (fun->IsBuiltin() && !fun->shared()->native())) {
13138 return false;
13139 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013140 }
13141 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013142}
13143
13144
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013145// Collect the raw data for a stack trace. Returns an array of 4
13146// element segments each containing a receiver, function, code and
13147// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013148RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013149 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013150 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013151 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013153 HandleScope scope(isolate);
13154 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013155
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013156 limit = Max(limit, 0); // Ensure that limit is not negative.
13157 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013158 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013159 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013160
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013161 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013162 // If the caller parameter is a function we skip frames until we're
13163 // under it before starting to collect.
13164 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013165 int cursor = 0;
13166 int frames_seen = 0;
13167 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013168 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013169 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013170 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013171 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013172 // Set initial size to the maximum inlining level + 1 for the outermost
13173 // function.
13174 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013175 frame->Summarize(&frames);
13176 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013177 if (cursor + 4 > elements->length()) {
13178 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13179 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013180 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013181 for (int i = 0; i < cursor; i++) {
13182 new_elements->set(i, elements->get(i));
13183 }
13184 elements = new_elements;
13185 }
13186 ASSERT(cursor + 4 <= elements->length());
13187
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013188 Handle<Object> recv = frames[i].receiver();
13189 Handle<JSFunction> fun = frames[i].function();
13190 Handle<Code> code = frames[i].code();
13191 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013192 elements->set(cursor++, *recv);
13193 elements->set(cursor++, *fun);
13194 elements->set(cursor++, *code);
13195 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013196 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013197 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013198 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013199 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013200 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013201 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013202 return *result;
13203}
13204
13205
ager@chromium.org3811b432009-10-28 14:53:37 +000013206// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013207RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013208 ASSERT_EQ(args.length(), 0);
13209
13210 NoHandleAllocation ha;
13211
13212 const char* version_string = v8::V8::GetVersion();
13213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013214 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13215 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013216}
13217
13218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013219RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013220 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013221 OS::PrintError("abort: %s\n",
13222 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013223 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013224 OS::Abort();
13225 UNREACHABLE();
13226 return NULL;
13227}
13228
13229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013230RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013231 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013232 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013233 Object* key = args[1];
13234
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013235 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013236 Object* o = cache->get(finger_index);
13237 if (o == key) {
13238 // The fastest case: hit the same place again.
13239 return cache->get(finger_index + 1);
13240 }
13241
13242 for (int i = finger_index - 2;
13243 i >= JSFunctionResultCache::kEntriesIndex;
13244 i -= 2) {
13245 o = cache->get(i);
13246 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013247 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013248 return cache->get(i + 1);
13249 }
13250 }
13251
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013252 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013253 ASSERT(size <= cache->length());
13254
13255 for (int i = size - 2; i > finger_index; i -= 2) {
13256 o = cache->get(i);
13257 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013258 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013259 return cache->get(i + 1);
13260 }
13261 }
13262
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013263 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013264 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013265
13266 Handle<JSFunctionResultCache> cache_handle(cache);
13267 Handle<Object> key_handle(key);
13268 Handle<Object> value;
13269 {
13270 Handle<JSFunction> factory(JSFunction::cast(
13271 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13272 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013273 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013274 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013275 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013276 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013277 value = Execution::Call(factory,
13278 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013279 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013280 argv,
13281 &pending_exception);
13282 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013283 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013284
13285#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013286 if (FLAG_verify_heap) {
13287 cache_handle->JSFunctionResultCacheVerify();
13288 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013289#endif
13290
13291 // Function invocation may have cleared the cache. Reread all the data.
13292 finger_index = cache_handle->finger_index();
13293 size = cache_handle->size();
13294
13295 // If we have spare room, put new data into it, otherwise evict post finger
13296 // entry which is likely to be the least recently used.
13297 int index = -1;
13298 if (size < cache_handle->length()) {
13299 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13300 index = size;
13301 } else {
13302 index = finger_index + JSFunctionResultCache::kEntrySize;
13303 if (index == cache_handle->length()) {
13304 index = JSFunctionResultCache::kEntriesIndex;
13305 }
13306 }
13307
13308 ASSERT(index % 2 == 0);
13309 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13310 ASSERT(index < cache_handle->length());
13311
13312 cache_handle->set(index, *key_handle);
13313 cache_handle->set(index + 1, *value);
13314 cache_handle->set_finger_index(index);
13315
13316#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013317 if (FLAG_verify_heap) {
13318 cache_handle->JSFunctionResultCacheVerify();
13319 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013320#endif
13321
13322 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013323}
13324
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013325
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013326RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013327 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013328 CONVERT_ARG_CHECKED(String, type, 0);
13329 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013330 return *isolate->factory()->NewJSMessageObject(
13331 type,
13332 arguments,
13333 0,
13334 0,
13335 isolate->factory()->undefined_value(),
13336 isolate->factory()->undefined_value(),
13337 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013338}
13339
13340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013341RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013342 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13343 return message->type();
13344}
13345
13346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013347RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013348 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13349 return message->arguments();
13350}
13351
13352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013353RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013354 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13355 return Smi::FromInt(message->start_position());
13356}
13357
13358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013359RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013360 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13361 return message->script();
13362}
13363
13364
kasper.lund44510672008-07-25 07:37:58 +000013365#ifdef DEBUG
13366// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13367// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013368RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013369 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013370 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013371#define COUNT_ENTRY(Name, argc, ressize) + 1
13372 int entry_count = 0
13373 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13374 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13375 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13376#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013377 Factory* factory = isolate->factory();
13378 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013379 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013380 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013381#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013382 { \
13383 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013384 Handle<String> name; \
13385 /* Inline runtime functions have an underscore in front of the name. */ \
13386 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013387 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013388 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13389 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013390 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013391 Vector<const char>(#Name, StrLength(#Name))); \
13392 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013393 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013394 pair_elements->set(0, *name); \
13395 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013396 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013397 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013398 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013399 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013400 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013401 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013402 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013403 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013404#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013405 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013406 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013407 return *result;
13408}
kasper.lund44510672008-07-25 07:37:58 +000013409#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013410
13411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013412RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013413 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013414 CONVERT_CHECKED(String, format, args[0]);
13415 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013416 String::FlatContent format_content = format->GetFlatContent();
13417 RUNTIME_ASSERT(format_content.IsAscii());
13418 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013419 LOGGER->LogRuntime(chars, elms);
13420 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013421}
13422
13423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013424RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013425 UNREACHABLE(); // implemented as macro in the parser
13426 return NULL;
13427}
13428
13429
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013430#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13431 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13432 CONVERT_CHECKED(JSObject, obj, args[0]); \
13433 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13434 }
13435
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013436ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013437ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13438ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13439ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13440ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13441ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13442ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13443ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13444ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13445ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13446ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13447ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13448ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13449ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13450
13451#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13452
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013453
13454RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13455 ASSERT(args.length() == 2);
13456 CONVERT_CHECKED(JSObject, obj1, args[0]);
13457 CONVERT_CHECKED(JSObject, obj2, args[1]);
13458 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13459}
13460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013461// ----------------------------------------------------------------------------
13462// Implementation of Runtime
13463
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013464#define F(name, number_of_args, result_size) \
13465 { Runtime::k##name, Runtime::RUNTIME, #name, \
13466 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013467
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013468
13469#define I(name, number_of_args, result_size) \
13470 { Runtime::kInline##name, Runtime::INLINE, \
13471 "_" #name, NULL, number_of_args, result_size },
13472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013473static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013474 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013475 INLINE_FUNCTION_LIST(I)
13476 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013477};
13478
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013480MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13481 Object* dictionary) {
13482 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013483 ASSERT(dictionary != NULL);
13484 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13485 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013486 Object* name_symbol;
13487 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013488 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013489 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13490 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013491 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013492 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13493 String::cast(name_symbol),
13494 Smi::FromInt(i),
13495 PropertyDetails(NONE, NORMAL));
13496 if (!maybe_dictionary->ToObject(&dictionary)) {
13497 // Non-recoverable failure. Calling code must restart heap
13498 // initialization.
13499 return maybe_dictionary;
13500 }
13501 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013502 }
13503 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013504}
13505
13506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013507const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13508 Heap* heap = name->GetHeap();
13509 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013510 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013511 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013512 int function_index = Smi::cast(smi_index)->value();
13513 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013514 }
13515 return NULL;
13516}
13517
13518
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013519const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013520 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13521}
13522
13523
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013524void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013525 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013526 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013527 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013528 if (isolate->heap()->new_space()->AddFreshPage()) {
13529 return;
13530 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013531 // Try to do a garbage collection; ignore it if it fails. The C
13532 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013533 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013534 } else {
13535 // Handle last resort GC and make sure to allow future allocations
13536 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013537 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013538 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013539 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013540}
13541
13542
13543} } // namespace v8::internal